SDL: gamepad hot-plugging

This commit is contained in:
Flyinghead 2019-02-12 15:56:44 +01:00
parent 8b5c2a3fac
commit 85b428c2e1
5 changed files with 78 additions and 48 deletions

View File

@ -137,7 +137,7 @@ unsigned int GamepadDevice::get_axis_range(u32 axis) {
std::string GamepadDevice::make_mapping_filename() std::string GamepadDevice::make_mapping_filename()
{ {
std::string mapping_file = std::string(api_name()) + "_" + name(); std::string mapping_file = api_name() + "_" + name();
std::replace(mapping_file.begin(), mapping_file.end(), '/', '-'); std::replace(mapping_file.begin(), mapping_file.end(), '/', '-');
std::replace(mapping_file.begin(), mapping_file.end(), '\\', '-'); std::replace(mapping_file.begin(), mapping_file.end(), '\\', '-');
std::replace(mapping_file.begin(), mapping_file.end(), ':', '-'); std::replace(mapping_file.begin(), mapping_file.end(), ':', '-');

View File

@ -26,8 +26,8 @@ class GamepadDevice
{ {
typedef void (*input_detected_cb)(u32 code); typedef void (*input_detected_cb)(u32 code);
public: public:
virtual const char* api_name() = 0; const std::string& api_name() { return _api_name; }
virtual const char* name() = 0; const std::string& name() { return _name; }
int maple_port() { return _maple_port; } int maple_port() { return _maple_port; }
void set_maple_port(int port) { _maple_port = port; } void set_maple_port(int port) { _maple_port = port; }
void gamepad_btn_input(u32 code, bool pressed); void gamepad_btn_input(u32 code, bool pressed);
@ -64,7 +64,7 @@ public:
static GamepadDevice *GetGamepad(int index); static GamepadDevice *GetGamepad(int index);
protected: protected:
GamepadDevice(int maple_port) : _maple_port(maple_port), input_mapper(NULL), _input_detected(NULL) { GamepadDevice(int maple_port, const char *api_name) : _api_name(api_name), _maple_port(maple_port), input_mapper(NULL), _input_detected(NULL) {
_gamepads_mutex.lock(); _gamepads_mutex.lock();
_gamepads.push_back(this); _gamepads.push_back(this);
_gamepads_mutex.unlock(); _gamepads_mutex.unlock();
@ -73,6 +73,7 @@ protected:
virtual void load_axis_min_max(u32 axis) {} virtual void load_axis_min_max(u32 axis) {}
std::string _name;
InputMapping *input_mapper; InputMapping *input_mapper;
std::map<u32, int> axis_min_values; std::map<u32, int> axis_min_values;
std::map<u32, unsigned int> axis_ranges; std::map<u32, unsigned int> axis_ranges;
@ -82,6 +83,7 @@ private:
unsigned int get_axis_range(u32 axis); unsigned int get_axis_range(u32 axis);
std::string make_mapping_filename(); std::string make_mapping_filename();
std::string _api_name;
int _maple_port; int _maple_port;
bool _detecting_button = false; bool _detecting_button = false;
input_detected_cb _input_detected; input_detected_cb _input_detected;

View File

@ -616,9 +616,9 @@ static void gui_display_settings()
GamepadDevice *gamepad = GamepadDevice::GetGamepad(i); GamepadDevice *gamepad = GamepadDevice::GetGamepad(i);
if (gamepad == NULL) if (gamepad == NULL)
continue; continue;
ImGui::Text("%s", gamepad->api_name()); ImGui::Text("%s", gamepad->api_name().c_str());
ImGui::NextColumn(); ImGui::NextColumn();
ImGui::Text("%s", gamepad->name()); ImGui::Text("%s", gamepad->name().c_str());
ImGui::NextColumn(); ImGui::NextColumn();
char port_name[32]; char port_name[32];
sprintf(port_name, "##mapleport%d", i); sprintf(port_name, "##mapleport%d", i);

View File

@ -10,6 +10,7 @@
#include "khronos/GL3/gl3w.h" #include "khronos/GL3/gl3w.h"
#endif #endif
#endif #endif
#include "hw/maple/maple_devs.h"
#include "sdl_gamepad.h" #include "sdl_gamepad.h"
#include "sdl_keyboard.h" #include "sdl_keyboard.h"
@ -23,8 +24,6 @@ static SDL_GLContext glcontext;
#endif #endif
#define WINDOW_HEIGHT 480 #define WINDOW_HEIGHT 480
static SDLGamepadDevice* sdl_gamepads[4] = { NULL };
static SDL_JoystickID joystick_ids[ARRAY_SIZE(sdl_gamepads)] = { 0 };
static SDLMouseGamepadDevice* sdl_mouse_gamepad = NULL; static SDLMouseGamepadDevice* sdl_mouse_gamepad = NULL;
static SDLKbGamepadDevice* sdl_kb_gamepad = NULL; static SDLKbGamepadDevice* sdl_kb_gamepad = NULL;
static SDLKeyboardDevice* sdl_keyboard = NULL; static SDLKeyboardDevice* sdl_keyboard = NULL;
@ -44,6 +43,25 @@ extern s32 mo_y_abs;
extern int screen_width, screen_height; extern int screen_width, screen_height;
static void sdl_open_joystick(int index)
{
SDL_Joystick *pJoystick = SDL_JoystickOpen(index);
if (pJoystick == NULL)
{
printf("SDL: Cannot open joystick %d\n", index + 1);
return;
}
new SDLGamepadDevice(index < MAPLE_PORTS ? index : -1, pJoystick); // TODO save/restore maple port
}
static void sdl_close_joystick(SDL_JoystickID instance)
{
SDLGamepadDevice *device = SDLGamepadDevice::GetSDLGamepad(instance);
if (device != NULL)
delete device;
}
void input_sdl_init() void input_sdl_init()
{ {
if (SDL_WasInit(SDL_INIT_JOYSTICK) == 0) if (SDL_WasInit(SDL_INIT_JOYSTICK) == 0)
@ -53,25 +71,10 @@ void input_sdl_init()
die("error initializing SDL Joystick subsystem"); die("error initializing SDL Joystick subsystem");
} }
} }
// Open joystick device
int numjoys = SDL_NumJoysticks();
printf("Number of Joysticks found = %i\n", numjoys);
for (int i = 0; i < numjoys && i < ARRAY_SIZE(sdl_gamepads); i++)
{
SDL_Joystick *pJoystick = SDL_JoystickOpen(i);
if (pJoystick == NULL)
{
printf("Cannot open joystick %d\n", i + 1);
continue;
}
joystick_ids[i] = SDL_JoystickInstanceID(pJoystick);
sdl_gamepads[i] = new SDLGamepadDevice(i, pJoystick);
}
SDL_SetRelativeMouseMode(SDL_FALSE); SDL_SetRelativeMouseMode(SDL_FALSE);
sdl_keyboard = new SDLKeyboardDevice(0); // FIXME ports! sdl_keyboard = new SDLKeyboardDevice(0); // FIXME maple ports!
sdl_kb_gamepad = new SDLKbGamepadDevice(0); sdl_kb_gamepad = new SDLKbGamepadDevice(0);
sdl_mouse_gamepad = new SDLMouseGamepadDevice(0); sdl_mouse_gamepad = new SDLMouseGamepadDevice(0);
} }
@ -113,20 +116,18 @@ void input_sdl_handle(u32 port)
break; break;
case SDL_JOYBUTTONDOWN: case SDL_JOYBUTTONDOWN:
case SDL_JOYBUTTONUP: case SDL_JOYBUTTONUP:
for (int i = 0; i < ARRAY_SIZE(sdl_gamepads); i++) {
if (joystick_ids[i] == event.jbutton.which) SDLGamepadDevice *device = SDLGamepadDevice::GetSDLGamepad((SDL_JoystickID)event.jbutton.which);
{ if (device != NULL)
sdl_gamepads[i]->gamepad_btn_input(event.jbutton.button, event.type == SDL_JOYBUTTONDOWN); device->gamepad_btn_input(event.jbutton.button, event.type == SDL_JOYBUTTONDOWN);
break; }
}
break; break;
case SDL_JOYAXISMOTION: case SDL_JOYAXISMOTION:
for (int i = 0; i < ARRAY_SIZE(sdl_gamepads); i++) {
if (joystick_ids[i] == event.jaxis.which) SDLGamepadDevice *device = SDLGamepadDevice::GetSDLGamepad((SDL_JoystickID)event.jaxis.which);
{ if (device != NULL)
sdl_gamepads[i]->gamepad_axis_input(event.jaxis.axis, event.jaxis.value); device->gamepad_axis_input(event.jaxis.axis, event.jaxis.value);
break; }
}
break; break;
case SDL_MOUSEMOTION: case SDL_MOUSEMOTION:
@ -153,6 +154,14 @@ void input_sdl_handle(u32 port)
} }
sdl_mouse_gamepad->gamepad_btn_input(event.button.button, event.button.state == SDL_PRESSED); sdl_mouse_gamepad->gamepad_btn_input(event.button.button, event.button.state == SDL_PRESSED);
break; break;
case SDL_JOYDEVICEADDED:
sdl_open_joystick(event.jdevice.which);
break;
case SDL_JOYDEVICEREMOVED:
sdl_close_joystick((SDL_JoystickID)event.jdevice.which);
break;
} }
} }
} }

View File

@ -44,29 +44,47 @@ public:
class SDLGamepadDevice : public GamepadDevice class SDLGamepadDevice : public GamepadDevice
{ {
public: public:
SDLGamepadDevice(int maple_port, SDL_Joystick* sdl_joystick) : GamepadDevice(maple_port), sdl_joystick(sdl_joystick) SDLGamepadDevice(int maple_port, SDL_Joystick* sdl_joystick) : GamepadDevice(maple_port, "SDL"), sdl_joystick(sdl_joystick)
{ {
_name = SDL_JoystickName(sdl_joystick); _name = SDL_JoystickName(sdl_joystick);
sdl_joystick_instance = SDL_JoystickInstanceID(sdl_joystick);
printf("SDL: Opened joystick on port %d: '%s' ", maple_port, _name.c_str());
if (!find_mapping()) if (!find_mapping())
{ {
if (_name == "Microsoft X-Box 360 pad") if (_name == "Microsoft X-Box 360 pad")
{ {
input_mapper = new Xbox360InputMapping(); input_mapper = new Xbox360InputMapping();
printf("Using Xbox 360 mapping\n"); printf("using Xbox 360 mapping\n");
} }
else else
{ {
input_mapper = new DefaultInputMapping(); input_mapper = new DefaultInputMapping();
printf("Using default mapping\n"); printf("using default mapping\n");
} }
save_mapping(); save_mapping();
} }
else
printf("using custom mapping '%s'\n", input_mapper->name.c_str());
auto it = sdl_gamepads.find(sdl_joystick_instance);
if (it != sdl_gamepads.end())
delete it->second;
sdl_gamepads[sdl_joystick_instance] = this;
} }
virtual const char* api_name() override { return "SDL"; }
virtual const char* name() override { return _name.c_str(); }
virtual ~SDLGamepadDevice() override virtual ~SDLGamepadDevice() override
{ {
printf("SDL: Joystick '%s' on port %d disconnected\n", _name.c_str(), maple_port());
SDL_JoystickClose(sdl_joystick); SDL_JoystickClose(sdl_joystick);
sdl_gamepads.erase(sdl_joystick_instance);
}
SDL_JoystickID sdl_instance() { return sdl_joystick_instance; }
static SDLGamepadDevice *GetSDLGamepad(SDL_JoystickID id)
{
auto it = sdl_gamepads.find(id);
if (it != sdl_gamepads.end())
return it->second;
else
return NULL;
} }
protected: protected:
@ -77,10 +95,13 @@ protected:
} }
private: private:
std::string _name;
SDL_Joystick* sdl_joystick; SDL_Joystick* sdl_joystick;
SDL_JoystickID sdl_joystick_instance;
static std::map<SDL_JoystickID, SDLGamepadDevice*> sdl_gamepads;
}; };
std::map<SDL_JoystickID, SDLGamepadDevice*> SDLGamepadDevice::sdl_gamepads;
class KbInputMapping : public InputMapping class KbInputMapping : public InputMapping
{ {
public: public:
@ -107,13 +128,12 @@ public:
class SDLKbGamepadDevice : public GamepadDevice class SDLKbGamepadDevice : public GamepadDevice
{ {
public: public:
SDLKbGamepadDevice(int maple_port) : GamepadDevice(maple_port) SDLKbGamepadDevice(int maple_port) : GamepadDevice(maple_port, "SDL")
{ {
_name = "Keyboard";
if (!find_mapping()) if (!find_mapping())
input_mapper = new KbInputMapping(); input_mapper = new KbInputMapping();
} }
virtual const char* api_name() override { return "SDL"; }
virtual const char* name() override { return "Keyboard"; }
virtual ~SDLKbGamepadDevice() {} virtual ~SDLKbGamepadDevice() {}
}; };
@ -134,13 +154,12 @@ public:
class SDLMouseGamepadDevice : public GamepadDevice class SDLMouseGamepadDevice : public GamepadDevice
{ {
public: public:
SDLMouseGamepadDevice(int maple_port) : GamepadDevice(maple_port) SDLMouseGamepadDevice(int maple_port) : GamepadDevice(maple_port, "SDL")
{ {
_name = "Mouse";
if (!find_mapping()) if (!find_mapping())
input_mapper = new MouseInputMapping(); input_mapper = new MouseInputMapping();
} }
virtual const char* api_name() override { return "SDL"; }
virtual const char* name() override { return "Mouse"; }
virtual ~SDLMouseGamepadDevice() {} virtual ~SDLMouseGamepadDevice() {}
}; };