diff --git a/core/sdl/sdl.cpp b/core/sdl/sdl.cpp index 687cc50d0..9c1ff308b 100644 --- a/core/sdl/sdl.cpp +++ b/core/sdl/sdl.cpp @@ -60,7 +60,7 @@ static void sdl_close_joystick(SDL_JoystickID instance) { std::shared_ptr gamepad = SDLGamepadDevice::GetSDLGamepad(instance); if (gamepad != NULL) - gamepad->Close(); + gamepad->close(); } void input_sdl_init() @@ -72,6 +72,8 @@ void input_sdl_init() die("error initializing SDL Joystick subsystem"); } } + if (SDL_WasInit(SDL_INIT_HAPTIC) == 0) + SDL_InitSubSystem(SDL_INIT_HAPTIC); SDL_SetRelativeMouseMode(SDL_FALSE); @@ -97,6 +99,9 @@ static void set_mouse_position(int x, int y) // FIXME this shouldn't be done by port. Need something like: handle_events() then get_port(0), get_port(2), ... void input_sdl_handle(u32 port) { + if (port == 0) // FIXME hack + SDLGamepadDevice::UpdateRumble(); + #define SET_FLAG(field, mask, expr) field =((expr) ? (field & ~mask) : (field | mask)) SDL_Event event; while (SDL_PollEvent(&event)) diff --git a/core/sdl/sdl_gamepad.h b/core/sdl/sdl_gamepad.h index 119b13e69..4d970a700 100644 --- a/core/sdl/sdl_gamepad.h +++ b/core/sdl/sdl_gamepad.h @@ -1,4 +1,5 @@ #include "../input/gamepad_device.h" +#include "oslib/oslib.h" #include "sdl.h" class DefaultInputMapping : public InputMapping @@ -65,13 +66,44 @@ public: } else printf("using custom mapping '%s'\n", input_mapper->name.c_str()); + sdl_haptic = SDL_HapticOpenFromJoystick(sdl_joystick); + if (SDL_HapticRumbleInit(sdl_haptic) != 0) + { + SDL_HapticClose(sdl_haptic); + sdl_haptic = NULL; + } + } - SDL_JoystickID sdl_instance() { return sdl_joystick_instance; } + virtual void rumble(float power, float inclination, u32 duration_ms) override + { + if (sdl_haptic != NULL) + { + vib_inclination = inclination * power; + vib_stop_time = os_GetSeconds() + duration_ms / 1000.0; - void Close() + SDL_HapticRumblePlay(sdl_haptic, power, duration_ms); + } + } + virtual void update_rumble() override + { + if (sdl_haptic == NULL) + return; + if (vib_inclination > 0) + { + int rem_time = (vib_stop_time - os_GetSeconds()) * 1000; + if (rem_time <= 0) + vib_inclination = 0; + else + SDL_HapticRumblePlay(sdl_haptic, vib_inclination * rem_time, rem_time); + } + } + + void close() { printf("SDL: Joystick '%s' on port %d disconnected\n", _name.c_str(), maple_port()); + if (sdl_haptic != NULL) + SDL_HapticClose(sdl_haptic); SDL_JoystickClose(sdl_joystick); GamepadDevice::Unregister(sdl_gamepads[sdl_joystick_instance]); sdl_gamepads.erase(sdl_joystick_instance); @@ -90,6 +122,11 @@ public: else return NULL; } + static void UpdateRumble() + { + for (auto pair : sdl_gamepads) + pair.second->update_rumble(); + } protected: virtual void load_axis_min_max(u32 axis) override @@ -101,6 +138,9 @@ protected: private: SDL_Joystick* sdl_joystick; SDL_JoystickID sdl_joystick_instance; + SDL_Haptic *sdl_haptic; + float vib_inclination = 0; + double vib_stop_time = 0; static std::map> sdl_gamepads; };