initial commit, 4.5 stable
Some checks failed
🔗 GHA / 📊 Static checks (push) Has been cancelled
🔗 GHA / 🤖 Android (push) Has been cancelled
🔗 GHA / 🍏 iOS (push) Has been cancelled
🔗 GHA / 🐧 Linux (push) Has been cancelled
🔗 GHA / 🍎 macOS (push) Has been cancelled
🔗 GHA / 🏁 Windows (push) Has been cancelled
🔗 GHA / 🌐 Web (push) Has been cancelled
Some checks failed
🔗 GHA / 📊 Static checks (push) Has been cancelled
🔗 GHA / 🤖 Android (push) Has been cancelled
🔗 GHA / 🍏 iOS (push) Has been cancelled
🔗 GHA / 🐧 Linux (push) Has been cancelled
🔗 GHA / 🍎 macOS (push) Has been cancelled
🔗 GHA / 🏁 Windows (push) Has been cancelled
🔗 GHA / 🌐 Web (push) Has been cancelled
This commit is contained in:
209
drivers/sdl/SCsub
Normal file
209
drivers/sdl/SCsub
Normal file
@@ -0,0 +1,209 @@
|
||||
#!/usr/bin/env python
|
||||
from misc.utility.scons_hints import *
|
||||
|
||||
Import("env")
|
||||
|
||||
env_sdl = env.Clone()
|
||||
|
||||
# Thirdparty source files
|
||||
|
||||
thirdparty_obj = []
|
||||
|
||||
if env["builtin_sdl"]:
|
||||
thirdparty_dir = "#thirdparty/sdl/"
|
||||
|
||||
# Use our own SDL_build_config_private.h.
|
||||
env_sdl.Prepend(CPPDEFINES=["SDL_PLATFORM_PRIVATE"])
|
||||
|
||||
# Common sources.
|
||||
|
||||
env_sdl.Prepend(
|
||||
CPPPATH=[
|
||||
thirdparty_dir,
|
||||
thirdparty_dir + "include",
|
||||
thirdparty_dir + "include/build_config",
|
||||
".", # SDL_build_config_private.h
|
||||
]
|
||||
)
|
||||
|
||||
thirdparty_sources = [
|
||||
"SDL.c",
|
||||
"SDL_assert.c",
|
||||
"SDL_error.c",
|
||||
"SDL_guid.c",
|
||||
"SDL_hashtable.c",
|
||||
"SDL_hints.c",
|
||||
"SDL_list.c",
|
||||
"SDL_log.c",
|
||||
"SDL_properties.c",
|
||||
"SDL_utils.c",
|
||||
"atomic/SDL_atomic.c",
|
||||
"atomic/SDL_spinlock.c",
|
||||
"events/SDL_events.c",
|
||||
"events/SDL_eventwatch.c",
|
||||
"haptic/SDL_haptic.c",
|
||||
"io/SDL_iostream.c",
|
||||
"joystick/SDL_gamepad.c",
|
||||
"joystick/SDL_joystick.c",
|
||||
"joystick/SDL_steam_virtual_gamepad.c",
|
||||
"joystick/controller_type.c",
|
||||
"libm/e_atan2.c",
|
||||
"libm/e_exp.c",
|
||||
"libm/e_fmod.c",
|
||||
"libm/e_log.c",
|
||||
"libm/e_log10.c",
|
||||
"libm/e_pow.c",
|
||||
"libm/e_rem_pio2.c",
|
||||
"libm/e_sqrt.c",
|
||||
"libm/k_cos.c",
|
||||
"libm/k_rem_pio2.c",
|
||||
"libm/k_sin.c",
|
||||
"libm/k_tan.c",
|
||||
"libm/s_atan.c",
|
||||
"libm/s_copysign.c",
|
||||
"libm/s_cos.c",
|
||||
"libm/s_fabs.c",
|
||||
"libm/s_floor.c",
|
||||
"libm/s_isinf.c",
|
||||
"libm/s_isinff.c",
|
||||
"libm/s_isnan.c",
|
||||
"libm/s_isnanf.c",
|
||||
"libm/s_modf.c",
|
||||
"libm/s_scalbn.c",
|
||||
"libm/s_sin.c",
|
||||
"libm/s_tan.c",
|
||||
"sensor/SDL_sensor.c",
|
||||
"sensor/dummy/SDL_dummysensor.c",
|
||||
"stdlib/SDL_crc16.c",
|
||||
"stdlib/SDL_crc32.c",
|
||||
"stdlib/SDL_getenv.c",
|
||||
"stdlib/SDL_iconv.c",
|
||||
"stdlib/SDL_malloc.c",
|
||||
"stdlib/SDL_memcpy.c",
|
||||
"stdlib/SDL_memmove.c",
|
||||
"stdlib/SDL_memset.c",
|
||||
"stdlib/SDL_mslibc.c",
|
||||
"stdlib/SDL_murmur3.c",
|
||||
"stdlib/SDL_qsort.c",
|
||||
"stdlib/SDL_random.c",
|
||||
"stdlib/SDL_stdlib.c",
|
||||
"stdlib/SDL_string.c",
|
||||
"stdlib/SDL_strtokr.c",
|
||||
"thread/SDL_thread.c",
|
||||
"timer/SDL_timer.c",
|
||||
]
|
||||
|
||||
# HIDAPI
|
||||
thirdparty_sources += [
|
||||
"hidapi/SDL_hidapi.c",
|
||||
"joystick/hidapi/SDL_hidapi_combined.c",
|
||||
"joystick/hidapi/SDL_hidapi_gamecube.c",
|
||||
"joystick/hidapi/SDL_hidapijoystick.c",
|
||||
"joystick/hidapi/SDL_hidapi_luna.c",
|
||||
"joystick/hidapi/SDL_hidapi_ps3.c",
|
||||
"joystick/hidapi/SDL_hidapi_ps4.c",
|
||||
"joystick/hidapi/SDL_hidapi_ps5.c",
|
||||
"joystick/hidapi/SDL_hidapi_rumble.c",
|
||||
"joystick/hidapi/SDL_hidapi_shield.c",
|
||||
"joystick/hidapi/SDL_hidapi_stadia.c",
|
||||
"joystick/hidapi/SDL_hidapi_steam.c",
|
||||
"joystick/hidapi/SDL_hidapi_steamdeck.c",
|
||||
"joystick/hidapi/SDL_hidapi_steam_hori.c",
|
||||
"joystick/hidapi/SDL_hidapi_switch.c",
|
||||
"joystick/hidapi/SDL_hidapi_wii.c",
|
||||
"joystick/hidapi/SDL_hidapi_xbox360.c",
|
||||
"joystick/hidapi/SDL_hidapi_xbox360w.c",
|
||||
"joystick/hidapi/SDL_hidapi_xboxone.c",
|
||||
]
|
||||
|
||||
# Platform specific sources.
|
||||
|
||||
if env["platform"] == "linuxbsd":
|
||||
# TODO: Check support for BSD systems.
|
||||
env_sdl.Append(CPPDEFINES=["SDL_PLATFORM_LINUX"])
|
||||
thirdparty_sources += [
|
||||
"core/linux/SDL_dbus.c",
|
||||
"core/linux/SDL_evdev.c",
|
||||
"core/linux/SDL_evdev_capabilities.c",
|
||||
"core/linux/SDL_evdev_kbd.c",
|
||||
"core/linux/SDL_fcitx.c",
|
||||
"core/linux/SDL_ibus.c",
|
||||
"core/linux/SDL_ime.c",
|
||||
"core/linux/SDL_system_theme.c",
|
||||
"core/linux/SDL_threadprio.c",
|
||||
"core/linux/SDL_udev.c",
|
||||
"core/unix/SDL_appid.c",
|
||||
"core/unix/SDL_poll.c",
|
||||
"haptic/linux/SDL_syshaptic.c",
|
||||
"joystick/linux/SDL_sysjoystick.c",
|
||||
"loadso/dlopen/SDL_sysloadso.c",
|
||||
"thread/pthread/SDL_syscond.c",
|
||||
"thread/pthread/SDL_sysmutex.c",
|
||||
"thread/pthread/SDL_sysrwlock.c",
|
||||
"thread/pthread/SDL_syssem.c",
|
||||
"thread/pthread/SDL_systhread.c",
|
||||
"thread/pthread/SDL_systls.c",
|
||||
"timer/unix/SDL_systimer.c",
|
||||
]
|
||||
env_sdl.Prepend(CPPPATH=[thirdparty_dir + "core/linux"])
|
||||
|
||||
elif env["platform"] == "macos":
|
||||
env_sdl.Append(CPPDEFINES=["SDL_PLATFORM_MACOS"])
|
||||
thirdparty_sources += [
|
||||
"core/unix/SDL_appid.c",
|
||||
"core/unix/SDL_poll.c",
|
||||
"haptic/darwin/SDL_syshaptic.c",
|
||||
"joystick/darwin/SDL_iokitjoystick.c",
|
||||
"joystick/apple/SDL_mfijoystick.m",
|
||||
"thread/pthread/SDL_syscond.c",
|
||||
"thread/pthread/SDL_sysmutex.c",
|
||||
"thread/pthread/SDL_sysrwlock.c",
|
||||
"thread/pthread/SDL_syssem.c",
|
||||
"thread/pthread/SDL_systhread.c",
|
||||
"thread/pthread/SDL_systls.c",
|
||||
"timer/unix/SDL_systimer.c",
|
||||
]
|
||||
|
||||
elif env["platform"] == "windows":
|
||||
env_sdl.Append(CPPDEFINES=["SDL_PLATFORM_WINDOWS"])
|
||||
thirdparty_sources += [
|
||||
"core/windows/SDL_gameinput.c",
|
||||
"core/windows/SDL_hid.c",
|
||||
"core/windows/SDL_immdevice.c",
|
||||
"core/windows/SDL_windows.c",
|
||||
"core/windows/SDL_xinput.c",
|
||||
"core/windows/pch.c",
|
||||
"haptic/windows/SDL_dinputhaptic.c",
|
||||
"haptic/windows/SDL_windowshaptic.c",
|
||||
"joystick/windows/SDL_dinputjoystick.c",
|
||||
"joystick/windows/SDL_rawinputjoystick.c",
|
||||
"joystick/windows/SDL_windows_gaming_input.c",
|
||||
"joystick/windows/SDL_windowsjoystick.c",
|
||||
"joystick/windows/SDL_xinputjoystick.c",
|
||||
"thread/generic/SDL_syscond.c",
|
||||
"thread/generic/SDL_sysrwlock.c",
|
||||
"thread/windows/SDL_syscond_cv.c",
|
||||
"thread/windows/SDL_sysmutex.c",
|
||||
"thread/windows/SDL_sysrwlock_srw.c",
|
||||
"thread/windows/SDL_syssem.c",
|
||||
"thread/windows/SDL_systhread.c",
|
||||
"thread/windows/SDL_systls.c",
|
||||
"timer/windows/SDL_systimer.c",
|
||||
]
|
||||
|
||||
thirdparty_sources = [thirdparty_dir + file for file in thirdparty_sources]
|
||||
|
||||
env_thirdparty = env_sdl.Clone()
|
||||
env_thirdparty.disable_warnings()
|
||||
env_thirdparty.add_source_files(thirdparty_obj, thirdparty_sources)
|
||||
env.drivers_sources += thirdparty_obj
|
||||
|
||||
# Godot source files
|
||||
|
||||
driver_obj = []
|
||||
|
||||
env_sdl.add_source_files(driver_obj, "*.cpp")
|
||||
env.drivers_sources += driver_obj
|
||||
|
||||
# Needed to force rebuilding the driver files when the thirdparty library is updated.
|
||||
env.Depends(driver_obj, thirdparty_obj)
|
142
drivers/sdl/SDL_build_config_private.h
Normal file
142
drivers/sdl/SDL_build_config_private.h
Normal file
@@ -0,0 +1,142 @@
|
||||
/**************************************************************************/
|
||||
/* SDL_build_config_private.h */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#define SDL_build_config_h_
|
||||
|
||||
#include <SDL3/SDL_platform_defines.h>
|
||||
|
||||
#define HAVE_STDARG_H 1
|
||||
#define HAVE_STDDEF_H 1
|
||||
|
||||
// Here we disable SDL subsystems that are not going to be used
|
||||
#define SDL_CPUINFO_DISABLED 1
|
||||
#define SDL_AUDIO_DISABLED 1
|
||||
#define SDL_PROCESS_DUMMY 1
|
||||
#define SDL_LOADSO_DUMMY 1
|
||||
#define SDL_VIDEO_DISABLED 1
|
||||
#define SDL_CAMERA_DISABLED 1
|
||||
#define SDL_DIALOG_DISABLED 1
|
||||
#define SDL_FILESYSTEM_DUMMY 1
|
||||
#define SDL_FSOPS_DUMMY 1
|
||||
#define SDL_SENSOR_DISABLED 1
|
||||
#define SDL_GPU_DISABLED 1
|
||||
#define SDL_RENDER_DISABLED 1
|
||||
#define SDL_POWER_DISABLED 1
|
||||
#define SDL_LEAN_AND_MEAN 1
|
||||
|
||||
// Windows defines
|
||||
#if defined(SDL_PLATFORM_WINDOWS)
|
||||
|
||||
#define SDL_PLATFORM_PRIVATE_NAME "Windows"
|
||||
#define HAVE_LIBC 1
|
||||
#define HAVE_DINPUT_H 1
|
||||
#define HAVE_XINPUT_H 1
|
||||
#if defined(_WIN32_MAXVER) && _WIN32_MAXVER >= 0x0A00 /* Windows 10 SDK */
|
||||
#define HAVE_WINDOWS_GAMING_INPUT_H 1
|
||||
#define SDL_JOYSTICK_WGI 1
|
||||
#endif
|
||||
#define SDL_JOYSTICK_DINPUT 1
|
||||
#define SDL_JOYSTICK_HIDAPI 1
|
||||
#define SDL_JOYSTICK_RAWINPUT 1
|
||||
#define SDL_JOYSTICK_XINPUT 1
|
||||
#define SDL_HAPTIC_DINPUT 1
|
||||
#define SDL_THREAD_GENERIC_COND_SUFFIX 1
|
||||
#define SDL_THREAD_GENERIC_RWLOCK_SUFFIX 1
|
||||
#define SDL_THREAD_WINDOWS 1
|
||||
#define SDL_TIMER_WINDOWS 1
|
||||
|
||||
// Linux defines
|
||||
#elif defined(SDL_PLATFORM_LINUX)
|
||||
|
||||
#define SDL_PLATFORM_PRIVATE_NAME "Linux"
|
||||
#define SDL_PLATFORM_UNIX 1
|
||||
|
||||
#define HAVE_STDIO_H 1
|
||||
#define HAVE_LINUX_INPUT_H 1
|
||||
#define HAVE_POLL 1
|
||||
|
||||
#ifdef __linux__
|
||||
#define HAVE_INOTIFY 1
|
||||
#define HAVE_INOTIFY_INIT1 1
|
||||
// Don't add these defines, for some reason they mess with C#'s ability
|
||||
// to use environment variables (see GH-109024)
|
||||
//#define HAVE_GETENV 1
|
||||
//#define HAVE_SETENV 1
|
||||
//#define HAVE_UNSETENV 1
|
||||
#endif
|
||||
|
||||
#ifdef DBUS_ENABLED
|
||||
#define HAVE_DBUS_DBUS_H 1
|
||||
#define SDL_USE_LIBDBUS 1
|
||||
// SOWRAP_ENABLED is handled in thirdparty/sdl/core/linux/SDL_dbus.c
|
||||
#endif
|
||||
|
||||
#ifdef UDEV_ENABLED
|
||||
#define HAVE_LIBUDEV_H 1
|
||||
#define SDL_USE_LIBUDEV
|
||||
#ifdef SOWRAP_ENABLED
|
||||
#define SDL_UDEV_DYNAMIC "libudev.so.1"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#define SDL_LOADSO_DLOPEN 1
|
||||
#define SDL_HAPTIC_LINUX 1
|
||||
#define SDL_TIMER_UNIX 1
|
||||
#define SDL_JOYSTICK_LINUX 1
|
||||
#define SDL_INPUT_LINUXEV 1
|
||||
#define SDL_THREAD_PTHREAD 1
|
||||
|
||||
// MacOS defines
|
||||
#elif defined(SDL_PLATFORM_MACOS)
|
||||
|
||||
#define SDL_PLATFORM_PRIVATE_NAME "macOS"
|
||||
#define SDL_PLATFORM_UNIX 1
|
||||
#define HAVE_STDIO_H 1
|
||||
#define HAVE_LIBC 1
|
||||
#define SDL_HAPTIC_IOKIT 1
|
||||
#define SDL_JOYSTICK_IOKIT 1
|
||||
#define SDL_JOYSTICK_MFI 1
|
||||
#define SDL_TIMER_UNIX 1
|
||||
#define SDL_THREAD_PTHREAD 1
|
||||
|
||||
// Other platforms are not supported (for now)
|
||||
#else
|
||||
#error "No SDL build config was found for this platform. Setup one before compiling the engine."
|
||||
#endif
|
||||
|
||||
#if !defined(HAVE_STDINT_H) && !defined(_STDINT_H_)
|
||||
#define HAVE_STDINT_H 1
|
||||
#endif /* !_STDINT_H_ && !HAVE_STDINT_H */
|
||||
|
||||
#ifdef __GNUC__
|
||||
#define HAVE_GCC_SYNC_LOCK_TEST_AND_SET 1
|
||||
#endif
|
292
drivers/sdl/joypad_sdl.cpp
Normal file
292
drivers/sdl/joypad_sdl.cpp
Normal file
@@ -0,0 +1,292 @@
|
||||
/**************************************************************************/
|
||||
/* joypad_sdl.cpp */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#include "joypad_sdl.h"
|
||||
|
||||
#ifdef SDL_ENABLED
|
||||
|
||||
#include "core/input/default_controller_mappings.h"
|
||||
#include "core/os/time.h"
|
||||
#include "core/variant/dictionary.h"
|
||||
|
||||
#include <iterator>
|
||||
|
||||
#include <SDL3/SDL.h>
|
||||
#include <SDL3/SDL_error.h>
|
||||
#include <SDL3/SDL_events.h>
|
||||
#include <SDL3/SDL_gamepad.h>
|
||||
#include <SDL3/SDL_iostream.h>
|
||||
#include <SDL3/SDL_joystick.h>
|
||||
|
||||
JoypadSDL *JoypadSDL::singleton = nullptr;
|
||||
|
||||
// Macro to skip the SDL joystick event handling if the device is an SDL gamepad, because
|
||||
// there are separate events for SDL gamepads
|
||||
#define SKIP_EVENT_FOR_GAMEPAD \
|
||||
if (SDL_IsGamepad(sdl_event.jdevice.which)) { \
|
||||
continue; \
|
||||
}
|
||||
|
||||
JoypadSDL::JoypadSDL() {
|
||||
singleton = this;
|
||||
}
|
||||
|
||||
#ifdef WINDOWS_ENABLED
|
||||
extern "C" {
|
||||
HWND SDL_HelperWindow;
|
||||
}
|
||||
|
||||
// Required for DInput joypads to work
|
||||
// TODO: remove this workaround when we update to newer version of SDL
|
||||
JoypadSDL::JoypadSDL(HWND p_helper_window) :
|
||||
JoypadSDL() {
|
||||
SDL_HelperWindow = p_helper_window;
|
||||
}
|
||||
#endif
|
||||
|
||||
JoypadSDL::~JoypadSDL() {
|
||||
// Process any remaining input events
|
||||
process_events();
|
||||
for (int i = 0; i < Input::JOYPADS_MAX; i++) {
|
||||
if (joypads[i].attached) {
|
||||
close_joypad(i);
|
||||
}
|
||||
}
|
||||
SDL_Quit();
|
||||
singleton = nullptr;
|
||||
}
|
||||
|
||||
JoypadSDL *JoypadSDL::get_singleton() {
|
||||
return singleton;
|
||||
}
|
||||
|
||||
Error JoypadSDL::initialize() {
|
||||
SDL_SetHint(SDL_HINT_JOYSTICK_THREAD, "1");
|
||||
SDL_SetHint(SDL_HINT_NO_SIGNAL_HANDLERS, "1");
|
||||
ERR_FAIL_COND_V_MSG(!SDL_Init(SDL_INIT_JOYSTICK | SDL_INIT_GAMEPAD), FAILED, SDL_GetError());
|
||||
|
||||
// Add Godot's mapping database from memory
|
||||
int i = 0;
|
||||
while (DefaultControllerMappings::mappings[i]) {
|
||||
String mapping_string = DefaultControllerMappings::mappings[i++];
|
||||
CharString data = mapping_string.utf8();
|
||||
SDL_IOStream *rw = SDL_IOFromMem((void *)data.ptr(), data.size());
|
||||
SDL_AddGamepadMappingsFromIO(rw, 1);
|
||||
}
|
||||
|
||||
// Make sure that we handle already connected joypads when the driver is initialized.
|
||||
process_events();
|
||||
|
||||
print_verbose("SDL: Init OK!");
|
||||
return OK;
|
||||
}
|
||||
|
||||
void JoypadSDL::process_events() {
|
||||
// Update rumble first for it to be applied when we handle SDL events
|
||||
for (int i = 0; i < Input::JOYPADS_MAX; i++) {
|
||||
Joypad &joy = joypads[i];
|
||||
if (joy.attached && joy.supports_force_feedback) {
|
||||
uint64_t timestamp = Input::get_singleton()->get_joy_vibration_timestamp(i);
|
||||
|
||||
// Update the joypad rumble only if there was a new vibration request
|
||||
if (timestamp > joy.ff_effect_timestamp) {
|
||||
joy.ff_effect_timestamp = timestamp;
|
||||
|
||||
SDL_Joystick *sdl_joy = SDL_GetJoystickFromID(joypads[i].sdl_instance_idx);
|
||||
Vector2 strength = Input::get_singleton()->get_joy_vibration_strength(i);
|
||||
|
||||
// If the vibration was requested to start, SDL_RumbleJoystick will start it.
|
||||
// If the vibration was requested to stop, strength and duration will be 0, so SDL will stop the rumble.
|
||||
SDL_RumbleJoystick(
|
||||
sdl_joy,
|
||||
// Rumble strength goes from 0 to 0xFFFF
|
||||
strength.x * UINT16_MAX,
|
||||
strength.y * UINT16_MAX,
|
||||
Input::get_singleton()->get_joy_vibration_duration(i) * 1000);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SDL_Event sdl_event;
|
||||
while (SDL_PollEvent(&sdl_event)) {
|
||||
// A new joypad was attached
|
||||
if (sdl_event.type == SDL_EVENT_JOYSTICK_ADDED) {
|
||||
int joy_id = Input::get_singleton()->get_unused_joy_id();
|
||||
if (joy_id == -1) {
|
||||
// There is no space for more joypads...
|
||||
print_error("A new joypad was attached but couldn't allocate a new id for it because joypad limit was reached.");
|
||||
} else {
|
||||
SDL_Joystick *joy = nullptr;
|
||||
SDL_Gamepad *gamepad = nullptr;
|
||||
String device_name;
|
||||
|
||||
// Gamepads must be opened with SDL_OpenGamepad to get their special remapped events
|
||||
if (SDL_IsGamepad(sdl_event.jdevice.which)) {
|
||||
gamepad = SDL_OpenGamepad(sdl_event.jdevice.which);
|
||||
|
||||
ERR_CONTINUE_MSG(!gamepad,
|
||||
vformat("Error opening gamepad at index %d: %s", sdl_event.jdevice.which, SDL_GetError()));
|
||||
|
||||
device_name = SDL_GetGamepadName(gamepad);
|
||||
joy = SDL_GetGamepadJoystick(gamepad);
|
||||
|
||||
print_verbose(vformat("SDL: Gamepad %s connected", SDL_GetGamepadName(gamepad)));
|
||||
} else {
|
||||
joy = SDL_OpenJoystick(sdl_event.jdevice.which);
|
||||
ERR_CONTINUE_MSG(!joy,
|
||||
vformat("Error opening joystick at index %d: %s", sdl_event.jdevice.which, SDL_GetError()));
|
||||
|
||||
device_name = SDL_GetJoystickName(joy);
|
||||
|
||||
print_verbose(vformat("SDL: Joystick %s connected", SDL_GetJoystickName(joy)));
|
||||
}
|
||||
|
||||
const int MAX_GUID_SIZE = 64;
|
||||
char guid[MAX_GUID_SIZE] = {};
|
||||
|
||||
SDL_GUIDToString(SDL_GetJoystickGUID(joy), guid, MAX_GUID_SIZE);
|
||||
SDL_PropertiesID propertiesID = SDL_GetJoystickProperties(joy);
|
||||
|
||||
joypads[joy_id].attached = true;
|
||||
joypads[joy_id].sdl_instance_idx = sdl_event.jdevice.which;
|
||||
joypads[joy_id].supports_force_feedback = SDL_GetBooleanProperty(propertiesID, SDL_PROP_JOYSTICK_CAP_RUMBLE_BOOLEAN, false);
|
||||
joypads[joy_id].guid = StringName(String(guid));
|
||||
|
||||
sdl_instance_id_to_joypad_id.insert(sdl_event.jdevice.which, joy_id);
|
||||
|
||||
Dictionary joypad_info;
|
||||
joypad_info["mapping_handled"] = true; // Skip Godot's mapping system because SDL already handles the joypad's mapping.
|
||||
joypad_info["raw_name"] = String(SDL_GetJoystickName(joy));
|
||||
joypad_info["vendor_id"] = itos(SDL_GetJoystickVendor(joy));
|
||||
joypad_info["product_id"] = itos(SDL_GetJoystickProduct(joy));
|
||||
|
||||
const uint64_t steam_handle = SDL_GetGamepadSteamHandle(gamepad);
|
||||
if (steam_handle != 0) {
|
||||
joypad_info["steam_input_index"] = itos(steam_handle);
|
||||
}
|
||||
|
||||
const int player_index = SDL_GetJoystickPlayerIndex(joy);
|
||||
if (player_index >= 0) {
|
||||
// For XInput controllers SDL_GetJoystickPlayerIndex returns the XInput user index.
|
||||
joypad_info["xinput_index"] = itos(player_index);
|
||||
}
|
||||
|
||||
Input::get_singleton()->joy_connection_changed(
|
||||
joy_id,
|
||||
true,
|
||||
device_name,
|
||||
joypads[joy_id].guid,
|
||||
joypad_info);
|
||||
}
|
||||
// An event for an attached joypad
|
||||
} else if (sdl_event.type >= SDL_EVENT_JOYSTICK_AXIS_MOTION && sdl_event.type < SDL_EVENT_FINGER_DOWN && sdl_instance_id_to_joypad_id.has(sdl_event.jdevice.which)) {
|
||||
int joy_id = sdl_instance_id_to_joypad_id.get(sdl_event.jdevice.which);
|
||||
|
||||
switch (sdl_event.type) {
|
||||
case SDL_EVENT_JOYSTICK_REMOVED:
|
||||
Input::get_singleton()->joy_connection_changed(joy_id, false, "");
|
||||
close_joypad(joy_id);
|
||||
break;
|
||||
|
||||
case SDL_EVENT_JOYSTICK_AXIS_MOTION:
|
||||
SKIP_EVENT_FOR_GAMEPAD;
|
||||
|
||||
Input::get_singleton()->joy_axis(
|
||||
joy_id,
|
||||
static_cast<JoyAxis>(sdl_event.jaxis.axis), // Godot joy axis constants are already intentionally the same as SDL's
|
||||
((sdl_event.jaxis.value - SDL_JOYSTICK_AXIS_MIN) / (float)(SDL_JOYSTICK_AXIS_MAX - SDL_JOYSTICK_AXIS_MIN) - 0.5f) * 2.0f);
|
||||
break;
|
||||
|
||||
case SDL_EVENT_JOYSTICK_BUTTON_UP:
|
||||
case SDL_EVENT_JOYSTICK_BUTTON_DOWN:
|
||||
SKIP_EVENT_FOR_GAMEPAD;
|
||||
|
||||
Input::get_singleton()->joy_button(
|
||||
joy_id,
|
||||
static_cast<JoyButton>(sdl_event.jbutton.button), // Godot button constants are intentionally the same as SDL's, so we can just straight up use them
|
||||
sdl_event.jbutton.down);
|
||||
break;
|
||||
|
||||
case SDL_EVENT_JOYSTICK_HAT_MOTION:
|
||||
SKIP_EVENT_FOR_GAMEPAD;
|
||||
|
||||
Input::get_singleton()->joy_hat(
|
||||
joy_id,
|
||||
(HatMask)sdl_event.jhat.value // Godot hat masks are identical to SDL hat masks, so we can just use them as-is.
|
||||
);
|
||||
break;
|
||||
|
||||
case SDL_EVENT_GAMEPAD_AXIS_MOTION: {
|
||||
float axis_value;
|
||||
|
||||
if (sdl_event.gaxis.axis == SDL_GAMEPAD_AXIS_LEFT_TRIGGER || sdl_event.gaxis.axis == SDL_GAMEPAD_AXIS_RIGHT_TRIGGER) {
|
||||
// Gamepad triggers go from 0 to SDL_JOYSTICK_AXIS_MAX
|
||||
axis_value = sdl_event.gaxis.value / (float)SDL_JOYSTICK_AXIS_MAX;
|
||||
} else {
|
||||
// Other axis go from SDL_JOYSTICK_AXIS_MIN to SDL_JOYSTICK_AXIS_MAX
|
||||
axis_value =
|
||||
((sdl_event.gaxis.value - SDL_JOYSTICK_AXIS_MIN) / (float)(SDL_JOYSTICK_AXIS_MAX - SDL_JOYSTICK_AXIS_MIN) - 0.5f) * 2.0f;
|
||||
}
|
||||
|
||||
Input::get_singleton()->joy_axis(
|
||||
joy_id,
|
||||
static_cast<JoyAxis>(sdl_event.gaxis.axis), // Godot joy axis constants are already intentionally the same as SDL's
|
||||
axis_value);
|
||||
} break;
|
||||
|
||||
// Do note SDL gamepads do not have separate events for the dpad
|
||||
case SDL_EVENT_GAMEPAD_BUTTON_UP:
|
||||
case SDL_EVENT_GAMEPAD_BUTTON_DOWN:
|
||||
Input::get_singleton()->joy_button(
|
||||
joy_id,
|
||||
static_cast<JoyButton>(sdl_event.gbutton.button), // Godot button constants are intentionally the same as SDL's, so we can just straight up use them
|
||||
sdl_event.gbutton.down);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void JoypadSDL::close_joypad(int p_pad_idx) {
|
||||
int sdl_instance_idx = joypads[p_pad_idx].sdl_instance_idx;
|
||||
|
||||
joypads[p_pad_idx].attached = false;
|
||||
sdl_instance_id_to_joypad_id.erase(sdl_instance_idx);
|
||||
|
||||
if (SDL_IsGamepad(sdl_instance_idx)) {
|
||||
SDL_Gamepad *gamepad = SDL_GetGamepadFromID(sdl_instance_idx);
|
||||
SDL_CloseGamepad(gamepad);
|
||||
} else {
|
||||
SDL_Joystick *joy = SDL_GetJoystickFromID(sdl_instance_idx);
|
||||
SDL_CloseJoystick(joy);
|
||||
}
|
||||
}
|
||||
|
||||
#endif // SDL_ENABLED
|
69
drivers/sdl/joypad_sdl.h
Normal file
69
drivers/sdl/joypad_sdl.h
Normal file
@@ -0,0 +1,69 @@
|
||||
/**************************************************************************/
|
||||
/* joypad_sdl.h */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "core/input/input.h"
|
||||
#include "core/os/thread.h"
|
||||
|
||||
typedef uint32_t SDL_JoystickID;
|
||||
typedef struct HWND__ *HWND;
|
||||
|
||||
class JoypadSDL {
|
||||
public:
|
||||
JoypadSDL();
|
||||
#ifdef WINDOWS_ENABLED
|
||||
JoypadSDL(HWND p_helper_window);
|
||||
#endif
|
||||
~JoypadSDL();
|
||||
|
||||
static JoypadSDL *get_singleton();
|
||||
|
||||
Error initialize();
|
||||
void process_events();
|
||||
|
||||
private:
|
||||
struct Joypad {
|
||||
bool attached = false;
|
||||
StringName guid;
|
||||
|
||||
SDL_JoystickID sdl_instance_idx;
|
||||
|
||||
bool supports_force_feedback = false;
|
||||
uint64_t ff_effect_timestamp = 0;
|
||||
};
|
||||
|
||||
static JoypadSDL *singleton;
|
||||
|
||||
Joypad joypads[Input::JOYPADS_MAX];
|
||||
HashMap<SDL_JoystickID, int> sdl_instance_id_to_joypad_id;
|
||||
|
||||
void close_joypad(int p_pad_idx);
|
||||
};
|
Reference in New Issue
Block a user