flycast/core/sdl/sdl_gamepad.h

233 lines
5.7 KiB
C
Raw Normal View History

#include "../input/gamepad_device.h"
2019-02-23 00:06:10 +00:00
#include "oslib/oslib.h"
#include "sdl.h"
2019-08-14 07:20:24 +00:00
#include "rend/gui.h"
class DefaultInputMapping : public InputMapping
{
public:
DefaultInputMapping()
{
name = "Default";
set_button(DC_BTN_Y, 0);
set_button(DC_BTN_B, 1);
set_button(DC_BTN_A, 2);
set_button(DC_BTN_X, 3);
set_button(DC_BTN_START, 9);
set_axis(DC_AXIS_X, 0, false);
set_axis(DC_AXIS_Y, 1, false);
set_axis(DC_AXIS_X2, 2, false);
set_axis(DC_AXIS_Y2, 3, false);
dirty = false;
}
};
class Xbox360InputMapping : public InputMapping
{
public:
Xbox360InputMapping()
{
name = "Xbox 360";
set_button(DC_BTN_A, 0);
set_button(DC_BTN_B, 1);
set_button(DC_BTN_X, 2);
set_button(DC_BTN_Y, 3);
set_button(DC_BTN_START, 7);
set_axis(DC_AXIS_X, 0, false);
set_axis(DC_AXIS_Y, 1, false);
set_axis(DC_AXIS_LT, 2, false);
set_axis(DC_AXIS_RT, 5, false);
set_axis(DC_DPAD_LEFT, 6, false);
set_axis(DC_DPAD_UP, 7, false);
dirty = false;
}
};
class SDLGamepadDevice : public GamepadDevice
{
public:
2019-02-12 14:56:44 +00:00
SDLGamepadDevice(int maple_port, SDL_Joystick* sdl_joystick) : GamepadDevice(maple_port, "SDL"), sdl_joystick(sdl_joystick)
{
_name = SDL_JoystickName(sdl_joystick);
2019-02-12 14:56:44 +00:00
sdl_joystick_instance = SDL_JoystickInstanceID(sdl_joystick);
2019-07-01 15:41:15 +00:00
INFO_LOG(INPUT, "SDL: Opened joystick on port %d: '%s'", maple_port, _name.c_str());
SDL_JoystickGUID guid = SDL_JoystickGetGUID(sdl_joystick);
char buf[33];
SDL_JoystickGetGUIDString(guid, buf, sizeof(buf));
_unique_id = buf;
if (_unique_id.empty())
_unique_id = _name;
if (!find_mapping())
{
if (_name == "Microsoft X-Box 360 pad")
{
input_mapper = std::make_shared<Xbox360InputMapping>();
2019-07-01 15:41:15 +00:00
INFO_LOG(INPUT, "using Xbox 360 mapping");
}
else
{
input_mapper = std::make_shared<DefaultInputMapping>();
2019-07-01 15:41:15 +00:00
INFO_LOG(INPUT, "using default mapping");
}
save_mapping();
}
2019-02-12 14:56:44 +00:00
else
2019-07-01 15:41:15 +00:00
INFO_LOG(INPUT, "using custom mapping '%s'", input_mapper->name.c_str());
2019-02-23 00:06:10 +00:00
sdl_haptic = SDL_HapticOpenFromJoystick(sdl_joystick);
if (SDL_HapticRumbleInit(sdl_haptic) != 0)
{
SDL_HapticClose(sdl_haptic);
sdl_haptic = NULL;
}
}
2019-02-23 00:06:10 +00:00
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;
2019-02-23 00:06:10 +00:00
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()
{
2019-07-01 15:41:15 +00:00
INFO_LOG(INPUT, "SDL: Joystick '%s' on port %d disconnected", _name.c_str(), maple_port());
2019-02-23 00:06:10 +00:00
if (sdl_haptic != NULL)
SDL_HapticClose(sdl_haptic);
SDL_JoystickClose(sdl_joystick);
GamepadDevice::Unregister(sdl_gamepads[sdl_joystick_instance]);
2019-02-12 14:56:44 +00:00
sdl_gamepads.erase(sdl_joystick_instance);
}
static void AddSDLGamepad(std::shared_ptr<SDLGamepadDevice> gamepad)
{
sdl_gamepads[gamepad->sdl_joystick_instance] = gamepad;
GamepadDevice::Register(gamepad);
}
static std::shared_ptr<SDLGamepadDevice> GetSDLGamepad(SDL_JoystickID id)
2019-02-12 14:56:44 +00:00
{
auto it = sdl_gamepads.find(id);
if (it != sdl_gamepads.end())
return it->second;
else
return NULL;
}
2019-02-23 00:06:10 +00:00
static void UpdateRumble()
{
for (auto& pair : sdl_gamepads)
2019-02-23 00:06:10 +00:00
pair.second->update_rumble();
}
protected:
virtual void load_axis_min_max(u32 axis) override
{
axis_min_values[axis] = -32768;
axis_ranges[axis] = 65535;
}
private:
SDL_Joystick* sdl_joystick;
2019-02-12 14:56:44 +00:00
SDL_JoystickID sdl_joystick_instance;
2019-02-23 00:06:10 +00:00
SDL_Haptic *sdl_haptic;
float vib_inclination = 0;
double vib_stop_time = 0;
static std::map<SDL_JoystickID, std::shared_ptr<SDLGamepadDevice>> sdl_gamepads;
};
std::map<SDL_JoystickID, std::shared_ptr<SDLGamepadDevice>> SDLGamepadDevice::sdl_gamepads;
2019-02-12 14:56:44 +00:00
class KbInputMapping : public InputMapping
{
public:
KbInputMapping()
{
name = "SDL Keyboard";
set_button(DC_BTN_A, SDLK_x);
set_button(DC_BTN_B, SDLK_c);
set_button(DC_BTN_X, SDLK_s);
set_button(DC_BTN_Y, SDLK_d);
set_button(DC_DPAD_UP, SDLK_UP);
set_button(DC_DPAD_DOWN, SDLK_DOWN);
set_button(DC_DPAD_LEFT, SDLK_LEFT);
set_button(DC_DPAD_RIGHT, SDLK_RIGHT);
set_button(DC_BTN_START, SDLK_RETURN);
set_button(EMU_BTN_TRIGGER_LEFT, SDLK_f);
set_button(EMU_BTN_TRIGGER_RIGHT, SDLK_v);
set_button(EMU_BTN_MENU, SDLK_TAB);
set_button(EMU_BTN_FFORWARD, SDLK_SPACE);
dirty = false;
}
};
class SDLKbGamepadDevice : public GamepadDevice
{
public:
2019-02-12 14:56:44 +00:00
SDLKbGamepadDevice(int maple_port) : GamepadDevice(maple_port, "SDL")
{
2019-02-12 14:56:44 +00:00
_name = "Keyboard";
2019-05-16 15:05:47 +00:00
_unique_id = "sdl_keyboard";
if (!find_mapping())
input_mapper = std::make_shared<KbInputMapping>();
}
virtual ~SDLKbGamepadDevice() {}
};
class MouseInputMapping : public InputMapping
{
public:
MouseInputMapping()
{
name = "SDL Mouse";
set_button(DC_BTN_A, SDL_BUTTON_LEFT);
set_button(DC_BTN_B, SDL_BUTTON_RIGHT);
set_button(DC_BTN_START, SDL_BUTTON_MIDDLE);
dirty = false;
}
};
class SDLMouseGamepadDevice : public GamepadDevice
{
public:
2019-02-12 14:56:44 +00:00
SDLMouseGamepadDevice(int maple_port) : GamepadDevice(maple_port, "SDL")
{
2019-02-12 14:56:44 +00:00
_name = "Mouse";
_unique_id = "sdl_mouse";
if (!find_mapping())
input_mapper = std::make_shared<MouseInputMapping>();
}
virtual ~SDLMouseGamepadDevice() {}
bool gamepad_btn_input(u32 code, bool pressed) override
{
if (gui_is_open())
// Don't register mouse clicks as gamepad presses when gui is open
// This makes the gamepad presses to be handled first and the mouse position to be ignored
// TODO Make this generic
return false;
else
return GamepadDevice::gamepad_btn_input(code, pressed);
}
};