summaryrefslogtreecommitdiffstatshomepage
path: root/src/osd/modules/input/input_sdl.cpp
diff options
context:
space:
mode:
author Vas Crabb <vas@vastheman.com>2023-01-13 17:26:33 +1100
committer Vas Crabb <vas@vastheman.com>2023-01-13 17:26:33 +1100
commite817a3d0c8e7697b55ce75c8e0939328022f5ecc (patch)
tree7e139ec16201682ad3ffaa87e5933815e9b4aa02 /src/osd/modules/input/input_sdl.cpp
parent58f41bfa47744ad7920386bbab1e594f9954519b (diff)
-osd: Improved SDL Game Controller joystick provider:
* Allow fallback to joystick API for devices without game controller mappings. * Detect controller reconnection. * Force Switch Pro Controller ZL/ZR to act like buttons. * Added button names for Google Stadia controller. * Also fixed dumb copy/paste error on my part in Windows clipboard code.
Diffstat (limited to 'src/osd/modules/input/input_sdl.cpp')
-rw-r--r--src/osd/modules/input/input_sdl.cpp551
1 files changed, 374 insertions, 177 deletions
diff --git a/src/osd/modules/input/input_sdl.cpp b/src/osd/modules/input/input_sdl.cpp
index bc29d6246f0..0a56d1b4f23 100644
--- a/src/osd/modules/input/input_sdl.cpp
+++ b/src/osd/modules/input/input_sdl.cpp
@@ -214,6 +214,29 @@ char const *const CONTROLLER_BUTTON_XBOX360[]{
"P4",
"Touchpad" };
+[[maybe_unused]] char const *const CONTROLLER_BUTTON_STADIA[]{
+ "A",
+ "B",
+ "X",
+ "Y",
+ "Options",
+ "Logo",
+ "Menu",
+ "L3",
+ "R3",
+ "L1",
+ "R1",
+ "D-pad Up",
+ "D-pad Down",
+ "D-pad Left",
+ "D-pad Right",
+ "Capture",
+ "P1",
+ "P2",
+ "P3",
+ "P4",
+ "Touchpad" };
+
struct key_lookup_table
{
int code;
@@ -785,6 +808,14 @@ public:
bool is_instance(SDL_JoystickID instance) const { return m_instance == instance; }
+ bool reconnect_match(std::string_view g, char const *s) const
+ {
+ return
+ (0 > m_instance) &&
+ (id() == g) &&
+ ((s && serial() && (*serial() == s)) || (!s && !serial()));
+ }
+
protected:
sdl_joystick_device_base(
running_machine &machine,
@@ -1006,7 +1037,7 @@ public:
break;
case SDL_JOYDEVICEREMOVED:
- osd_printf_verbose("Joystick: %s [GUID %s] disconnected\n", name(), id());
+ osd_printf_verbose("Joystick: %s [ID %s] disconnected\n", name(), id());
clear_instance();
reset();
if (m_joydevice)
@@ -1028,14 +1059,6 @@ public:
return m_hapdevice != nullptr;
}
- bool reconnect_match(std::string_view g, char const *s) const
- {
- return
- !m_joydevice &&
- (id() == g) &&
- ((s && serial() && (*serial() == s)) || (!s && !serial()));
- }
-
void attach_device(SDL_Joystick *joy)
{
assert(joy);
@@ -1044,6 +1067,8 @@ public:
set_instance(SDL_JoystickInstanceID(joy));
m_joydevice = joy;
m_hapdevice = SDL_HapticOpenFromJoystick(joy);
+
+ osd_printf_verbose("Joystick: %s [ID %s] reconnected\n", name(), id());
}
protected:
@@ -1138,6 +1163,7 @@ public:
{
char const *const *axisnames = CONTROLLER_AXIS_XBOX;
char const *const *buttonnames = CONTROLLER_BUTTON_XBOX360;
+ bool digitaltriggers = false;
#if SDL_VERSION_ATLEAST(2, 0, 12)
auto const ctrltype = SDL_GameControllerGetType(m_ctrldevice);
switch (ctrltype)
@@ -1169,6 +1195,7 @@ public:
osd_printf_verbose("Game Controller: ... Switch Pro Controller type\n");
axisnames = CONTROLLER_AXIS_SWITCH;
buttonnames = CONTROLLER_BUTTON_SWITCH;
+ digitaltriggers = true;
break;
#if SDL_VERSION_ATLEAST(2, 0, 14) // TODO: support more controller types
//case SDL_CONTROLLER_TYPE_VIRTUAL:
@@ -1178,13 +1205,17 @@ public:
buttonnames = CONTROLLER_BUTTON_PS5;
break;
//case SDL_CONTROLLER_TYPE_AMAZON_LUNA:
- //case SDL_CONTROLLER_TYPE_GOOGLE_STADIA:
+ case SDL_CONTROLLER_TYPE_GOOGLE_STADIA:
+ osd_printf_verbose("Game Controller: ... Google Stadia type\n");
+ axisnames = CONTROLLER_AXIS_PS;
+ buttonnames = CONTROLLER_BUTTON_STADIA;
+ break;
//case SDL_CONTROLLER_TYPE_SWITCH_JOYCON_LEFT:
//case SDL_CONTROLLER_TYPE_SWITCH_JOYCON_RIGHT:
//case SDL_CONTROLLER_TYPE_SWITCH_JOYCON_PAIR:
#endif
default: // default to Xbox 360 names
- osd_printf_verbose("Game Controller: ... unrecognised type (%d)\n", int(ctrltype));
+ osd_printf_verbose("Game Controller: ... unrecognized type (%d)\n", int(ctrltype));
break;
}
#endif
@@ -1199,9 +1230,9 @@ public:
{ SDL_CONTROLLER_AXIS_TRIGGERRIGHT, ITEM_ID_SLIDER2, true } };
for (auto [axis, item, buttontest] : axes)
{
- bool avail = true;
+ bool avail = !buttontest || !digitaltriggers;
#if SDL_VERSION_ATLEAST(2, 0, 14)
- avail = SDL_GameControllerHasAxis(m_ctrldevice, axis);
+ avail = avail && SDL_GameControllerHasAxis(m_ctrldevice, axis);
#endif
if (avail)
{
@@ -1293,10 +1324,13 @@ public:
auto const binding = SDL_GameControllerGetBindForAxis(m_ctrldevice, axis);
switch (binding.bindType)
{
+ case SDL_CONTROLLER_BINDTYPE_NONE:
+ avail = false;
+ break;
case SDL_CONTROLLER_BINDTYPE_BUTTON:
break;
default:
- avail = false;
+ avail = digitaltriggers;
}
}
if (avail)
@@ -1381,7 +1415,7 @@ public:
break;
case SDL_CONTROLLERDEVICEREMOVED:
- osd_printf_verbose("Game Controller: %s [GUID %s] disconnected\n", name(), id());
+ osd_printf_verbose("Game Controller: %s [ID %s] disconnected\n", name(), id());
clear_instance();
reset();
if (m_ctrldevice)
@@ -1393,6 +1427,17 @@ public:
}
}
+ void attach_device(SDL_GameController *ctrl)
+ {
+ assert(ctrl);
+ assert(!m_ctrldevice);
+
+ set_instance(SDL_JoystickInstanceID(SDL_GameControllerGetJoystick(ctrl)));
+ m_ctrldevice = ctrl;
+
+ osd_printf_verbose("Game Controller: %s [ID %s] reconnected\n", name(), id());
+ }
+
private:
// state information for a game controller
struct sdl_controller_state
@@ -1633,99 +1678,190 @@ public:
//============================================================
-// sdl_joystick_module
+// sdl_joystick_module_base
//============================================================
-class sdl_joystick_module : public sdl_input_module
+class sdl_joystick_module_base : public sdl_input_module
{
-public:
- sdl_joystick_module() :
- sdl_input_module(OSD_JOYSTICKINPUT_PROVIDER, "sdljoy"),
+protected:
+ sdl_joystick_module_base(char const *name) :
+ sdl_input_module(OSD_JOYSTICKINPUT_PROVIDER, name),
m_initialized_joystick(false),
m_initialized_haptic(false)
{
}
- virtual void exit() override
+ virtual ~sdl_joystick_module_base()
{
- sdl_input_module::exit();
-
- if (m_initialized_joystick)
- SDL_QuitSubSystem(SDL_INIT_JOYSTICK);
-
- if (m_initialized_haptic)
- SDL_QuitSubSystem(SDL_INIT_HAPTIC);
+ assert(!m_initialized_joystick);
+ assert(!m_initialized_haptic);
}
- virtual void input_init(running_machine &machine) override
+ bool have_joystick() const { return m_initialized_joystick; }
+ bool have_haptic() const { return m_initialized_haptic; }
+
+ void init_joystick()
{
- SDL_SetHint(SDL_HINT_ACCELEROMETER_AS_JOYSTICK, "0");
+ assert(!m_initialized_joystick);
+ assert(!m_initialized_haptic);
m_initialized_joystick = !SDL_InitSubSystem(SDL_INIT_JOYSTICK);
if (!m_initialized_joystick)
{
- osd_printf_error("Could not initialize SDL Joystick: %s.\n", SDL_GetError());
+ osd_printf_error("Could not initialize SDL Joystick subsystem: %s.\n", SDL_GetError());
return;
}
m_initialized_haptic = !SDL_InitSubSystem(SDL_INIT_HAPTIC);
if (!m_initialized_haptic)
- {
osd_printf_verbose("Could not initialize SDL Haptic subsystem: %s.\n", SDL_GetError());
- }
+ }
- sdl_input_module::input_init(machine);
+ void quit_joystick()
+ {
+ if (m_initialized_joystick)
+ {
+ SDL_QuitSubSystem(SDL_INIT_JOYSTICK);
+ m_initialized_joystick = false;
+ }
- bool const sixaxis_mode = downcast<const sdl_options *>(options())->sixaxis();
+ if (m_initialized_haptic)
+ {
+ SDL_QuitSubSystem(SDL_INIT_HAPTIC);
+ m_initialized_haptic = false;
+ }
+ }
- osd_printf_verbose("Joystick: Start initialization\n");
- for (int physical_stick = 0; physical_stick < SDL_NumJoysticks(); physical_stick++)
+ sdl_joystick_device *create_joystick_device(running_machine &machine, int index, bool sixaxis)
+ {
+ // open the joystick device
+ SDL_Joystick *const joy = SDL_JoystickOpen(index);
+ if (!joy)
{
- SDL_Joystick *const joy = SDL_JoystickOpen(physical_stick);
- char const *const name = SDL_JoystickName(joy);
- SDL_JoystickGUID guid = SDL_JoystickGetGUID(joy);
- char guid_str[256];
- guid_str[0] = '\0';
- SDL_JoystickGetGUIDString(guid, guid_str, sizeof(guid_str) - 1);
- char const *serial = nullptr;
+ osd_printf_error("Joystick: Could not open SDL joystick %d: %s.\n", index, SDL_GetError());
+ return nullptr;
+ }
+
+ // get basic info
+ char const *const name = SDL_JoystickName(joy);
+ SDL_JoystickGUID guid = SDL_JoystickGetGUID(joy);
+ char guid_str[256];
+ guid_str[0] = '\0';
+ SDL_JoystickGetGUIDString(guid, guid_str, sizeof(guid_str) - 1);
+ char const *serial = nullptr;
#if SDL_VERSION_ATLEAST(2, 0, 14)
- serial = SDL_JoystickGetSerial(joy);
+ serial = SDL_JoystickGetSerial(joy);
#endif
- std::string id(guid_str);
- if (serial)
- id.append(1, '-').append(serial);
+ std::string id(guid_str);
+ if (serial)
+ id.append(1, '-').append(serial);
+
+ // instantiate device
+ sdl_joystick_device &devinfo = sixaxis
+ ? devicelist().create_device<sdl_sixaxis_joystick_device>(machine, name ? name : guid_str, guid_str, *this, joy, serial)
+ : devicelist().create_device<sdl_joystick_device>(machine, name ? name : guid_str, guid_str, *this, joy, serial);
+
+ // print some diagnostic info
+ osd_printf_verbose("Joystick: %s [GUID %s] Vendor ID %04X, Product ID %04X, Revision %04X, Serial %s\n",
+ name ? name : "<nullptr>",
+ guid_str,
+ SDL_JoystickGetVendor(joy),
+ SDL_JoystickGetProduct(joy),
+ SDL_JoystickGetProductVersion(joy),
+ serial ? serial : "<nullptr>");
+ osd_printf_verbose("Joystick: ... %d axes, %d buttons %d hats %d balls\n",
+ SDL_JoystickNumAxes(joy),
+ SDL_JoystickNumButtons(joy),
+ SDL_JoystickNumHats(joy),
+ SDL_JoystickNumBalls(joy));
+ if (devinfo.has_haptic())
+ osd_printf_verbose("Joystick: ... Has haptic capability\n");
+ else
+ osd_printf_verbose("Joystick: ... Does not have haptic capability\n");
+ if (SDL_JoystickNumButtons(joy) > MAX_BUTTONS)
+ osd_printf_verbose("Joystick: ... Has %d buttons which exceeds supported %d buttons\n", SDL_JoystickNumButtons(joy), MAX_BUTTONS);
- sdl_joystick_device *const devinfo = sixaxis_mode
- ? &devicelist().create_device<sdl_sixaxis_joystick_device>(machine, name ? name : guid_str, guid_str, *this, joy, serial)
- : &devicelist().create_device<sdl_joystick_device>(machine, name ? name : guid_str, guid_str, *this, joy, serial);
+ // let it add controls
+ devinfo.configure();
+ return &devinfo;
+ }
- if (!devinfo)
- {
- SDL_JoystickClose(joy);
- continue;
- }
+ void dispatch_joystick_event(SDL_Event const &event)
+ {
+ // figure out which joystick this event is destined for
+ sdl_joystick_device_base *const target_device = find_joystick(event.jdevice.which); // FIXME: this depends on SDL_JoystickID being the same size as Sint32
- osd_printf_verbose("Joystick: %s [GUID %s] Vendor ID %04X, Product ID %04X, Revision %04X, Serial %s\n",
- name ? name : "<nullptr>",
- guid_str,
- SDL_JoystickGetVendor(joy),
- SDL_JoystickGetProduct(joy),
- SDL_JoystickGetProductVersion(joy),
- serial ? serial : "<nullptr>");
- osd_printf_verbose("Joystick: ... %d axes, %d buttons %d hats %d balls\n",
- SDL_JoystickNumAxes(joy),
- SDL_JoystickNumButtons(joy),
- SDL_JoystickNumHats(joy),
- SDL_JoystickNumBalls(joy));
- if (devinfo->has_haptic())
- osd_printf_verbose("Joystick: ... Has haptic capability\n");
- else
- osd_printf_verbose("Joystick: ... Does not have haptic capability\n");
- if (SDL_JoystickNumButtons(joy) > MAX_BUTTONS)
- osd_printf_verbose("Joystick: ... Has %d buttons which exceeds supported %d buttons\n", SDL_JoystickNumButtons(joy), MAX_BUTTONS);
+ // if we find a matching joystick, dispatch the event to the joystick
+ if (target_device)
+ target_device->queue_events(&event, 1);
+ }
+
+ device_info *find_reconnect_match(SDL_JoystickGUID const &guid, char const *serial)
+ {
+ char guid_str[256];
+ guid_str[0] = '\0';
+ SDL_JoystickGetGUIDString(guid, guid_str, sizeof(guid_str) - 1);
+ auto target_device = std::find_if(
+ devicelist().begin(),
+ devicelist().end(),
+ [&guid_str, &serial] (auto const &device)
+ {
+ auto &devinfo = downcast<sdl_joystick_device_base &>(*device);
+ return devinfo.reconnect_match(guid_str, serial);
+ });
+ return (devicelist().end() != target_device) ? target_device->get() : nullptr;
+ }
- devinfo->configure();
+ sdl_joystick_device_base *find_joystick(SDL_JoystickID instance)
+ {
+ for (auto &ptr : devicelist())
+ {
+ sdl_joystick_device_base *const device = downcast<sdl_joystick_device_base *>(ptr.get());
+ if (device->is_instance(instance))
+ return device;
}
+ return nullptr;
+ }
+
+private:
+ bool m_initialized_joystick;
+ bool m_initialized_haptic;
+};
+
+
+//============================================================
+// sdl_joystick_module
+//============================================================
+
+class sdl_joystick_module : public sdl_joystick_module_base
+{
+public:
+ sdl_joystick_module() : sdl_joystick_module_base("sdljoy")
+ {
+ }
+
+ virtual void exit() override
+ {
+ sdl_joystick_module_base::exit();
+
+ quit_joystick();
+ }
+
+ virtual void input_init(running_machine &machine) override
+ {
+ SDL_SetHint(SDL_HINT_ACCELEROMETER_AS_JOYSTICK, "0");
+
+ init_joystick();
+ if (!have_joystick())
+ return;
+
+ sdl_joystick_module_base::input_init(machine);
+
+ bool const sixaxis_mode = downcast<const sdl_options *>(options())->sixaxis();
+
+ osd_printf_verbose("Joystick: Start initialization\n");
+ for (int physical_stick = 0; physical_stick < SDL_NumJoysticks(); physical_stick++)
+ create_joystick_device(machine, physical_stick, sixaxis_mode);
static int const event_types[] = {
int(SDL_JOYAXISMOTION),
@@ -1735,7 +1871,6 @@ public:
int(SDL_JOYBUTTONUP),
int(SDL_JOYDEVICEADDED),
int(SDL_JOYDEVICEREMOVED) };
-
sdl_event_manager::instance().subscribe(event_types, this);
osd_printf_verbose("Joystick: End initialization\n");
@@ -1746,29 +1881,22 @@ public:
if (SDL_JOYDEVICEADDED == sdlevent.type)
{
SDL_Joystick *const joy = SDL_JoystickOpen(sdlevent.jdevice.which);
- if (joy)
+ if (!joy)
+ {
+ osd_printf_error("Joystick: Could not open SDL joystick %d: %s.\n", sdlevent.jdevice.which, SDL_GetError());
+ }
+ else
{
SDL_JoystickGUID guid = SDL_JoystickGetGUID(joy);
- char guid_str[256];
- guid_str[0] = '\0';
- SDL_JoystickGetGUIDString(guid, guid_str, sizeof(guid_str) - 1);
char const *serial = nullptr;
#if SDL_VERSION_ATLEAST(2, 0, 14)
serial = SDL_JoystickGetSerial(joy);
#endif
- auto target_device = std::find_if(
- devicelist().begin(),
- devicelist().end(),
- [&guid_str, &serial] (auto const &device)
- {
- auto &devinfo = downcast<sdl_joystick_device &>(*device);
- return devinfo.reconnect_match(guid_str, serial);
- });
- if (devicelist().end() != target_device)
+ auto *const target_device = find_reconnect_match(guid, serial);
+ if (target_device)
{
- auto &devinfo = downcast<sdl_joystick_device &>(**target_device);
+ auto &devinfo = downcast<sdl_joystick_device &>(*target_device);
devinfo.attach_device(joy);
- osd_printf_verbose("Joystick: %s [GUID %s] reconnected\n", devinfo.name(), guid_str);
}
else
{
@@ -1778,29 +1906,9 @@ public:
}
else
{
- // figure out which joystick this event is destined for
- sdl_joystick_device *const target_device = find_joystick(sdlevent.jdevice.which); // FIXME: this depends on SDL_JoystickID being the same size as Sint32
-
- // if we find a matching joystick, dispatch the event to the joystick
- if (target_device)
- target_device->queue_events(&sdlevent, 1);
- }
- }
-
-private:
- sdl_joystick_device *find_joystick(SDL_JoystickID instance)
- {
- for (auto &ptr : devicelist())
- {
- sdl_joystick_device *const device = downcast<sdl_joystick_device *>(ptr.get());
- if (device->is_instance(instance))
- return device;
+ dispatch_joystick_event(sdlevent);
}
- return nullptr;
}
-
- bool m_initialized_joystick;
- bool m_initialized_haptic;
};
@@ -1808,11 +1916,11 @@ private:
// sdl_game_controller_module
//============================================================
-class sdl_game_controller_module : public sdl_input_module
+class sdl_game_controller_module : public sdl_joystick_module_base
{
public:
sdl_game_controller_module() :
- sdl_input_module(OSD_JOYSTICKINPUT_PROVIDER, "sdlgame"),
+ sdl_joystick_module_base("sdlgame"),
m_initialized_game_controller(false)
{
}
@@ -1823,80 +1931,58 @@ public:
if (m_initialized_game_controller)
SDL_QuitSubSystem(SDL_INIT_GAMECONTROLLER);
+
+ quit_joystick();
}
virtual void input_init(running_machine &machine) override
{
+ SDL_SetHint(SDL_HINT_ACCELEROMETER_AS_JOYSTICK, "0");
+
+ init_joystick();
+ if (!have_joystick())
+ return;
+
m_initialized_game_controller = !SDL_InitSubSystem(SDL_INIT_GAMECONTROLLER);
if (!m_initialized_game_controller)
- {
- osd_printf_error("Could not initialize SDL Game Controller: %s.\n", SDL_GetError());
- return;
- }
+ osd_printf_warning("Could not initialize SDL Game Controller: %s.\n", SDL_GetError());
- sdl_input_module::input_init(machine);
+ sdl_joystick_module_base::input_init(machine);
+
+ bool const sixaxis_mode = downcast<const sdl_options *>(options())->sixaxis();
osd_printf_verbose("Game Controller: Start initialization\n");
for (int physical_stick = 0; physical_stick < SDL_NumJoysticks(); physical_stick++)
{
- if (!SDL_IsGameController(physical_stick))
- continue;
-
- SDL_GameController *const ctrl = SDL_GameControllerOpen(physical_stick);
- char const *const name = SDL_GameControllerName(ctrl);
- SDL_JoystickGUID guid = SDL_JoystickGetDeviceGUID(physical_stick);
- char guid_str[256];
- guid_str[0] = '\0';
- SDL_JoystickGetGUIDString(guid, guid_str, sizeof(guid_str) - 1);
- char const *serial = nullptr;
-#if SDL_VERSION_ATLEAST(2, 0, 14)
- serial = SDL_GameControllerGetSerial(ctrl);
-#endif
- std::string id(guid_str);
- if (serial)
- id.append(1, '-').append(serial);
-
- sdl_game_controller_device *const devinfo = &devicelist().create_device<sdl_game_controller_device>(
- machine,
- name ? name : guid_str,
- guid_str,
- *this,
- ctrl,
- serial);
-
- if (!devinfo)
+ // try to open as a game controller
+ SDL_GameController *ctrl = nullptr;
+ if (m_initialized_game_controller && SDL_IsGameController(physical_stick))
{
- SDL_GameControllerClose(ctrl);
- continue;
+ ctrl = SDL_GameControllerOpen(physical_stick);
+ if (!ctrl)
+ osd_printf_warning("Game Controller: Could not open SDL game controller %d: %s.\n", physical_stick, SDL_GetError());
}
- osd_printf_verbose("Game Controller: %s [GUID %s] Vendor ID %04X, Product ID %04X, Revision %04X, Serial %s\n",
- name ? name : "<nullptr>",
- guid_str,
- SDL_GameControllerGetVendor(ctrl),
- SDL_GameControllerGetProduct(ctrl),
- SDL_GameControllerGetProductVersion(ctrl),
- serial ? serial : "<nullptr>");
- char *const mapping = SDL_GameControllerMapping(ctrl);
- if (mapping)
- {
- osd_printf_verbose("Game Controller: ... mapping [%s]\n", mapping);
- SDL_free(mapping);
- }
+ // fall back to joystick API if necessary
+ if (!ctrl)
+ create_joystick_device(machine, physical_stick, sixaxis_mode);
else
- {
- osd_printf_verbose("Game Controller: ... no mapping\n");
- }
-
- devinfo->configure();
+ create_game_controller_device(machine, physical_stick, ctrl);
}
static int const event_types[] = {
+ int(SDL_JOYAXISMOTION),
+ int(SDL_JOYBALLMOTION),
+ int(SDL_JOYHATMOTION),
+ int(SDL_JOYBUTTONDOWN),
+ int(SDL_JOYBUTTONUP),
+ int(SDL_JOYDEVICEADDED),
+ int(SDL_JOYDEVICEREMOVED),
int(SDL_CONTROLLERAXISMOTION),
int(SDL_CONTROLLERBUTTONDOWN),
int(SDL_CONTROLLERBUTTONUP),
+ int(SDL_CONTROLLERDEVICEADDED),
int(SDL_CONTROLLERDEVICEREMOVED) };
-
sdl_event_manager::instance().subscribe(event_types, this);
osd_printf_verbose("Game Controller: End initialization\n");
@@ -1904,24 +1990,135 @@ public:
virtual void handle_event(SDL_Event &sdlevent) override
{
- // figure out which game controller this event is destined for
- sdl_game_controller_device *const target_device = find_controller(sdlevent.jdevice.which); // FIXME: this depends on SDL_JoystickID being the same size as Sint32
+ switch (sdlevent.type)
+ {
+ case SDL_JOYDEVICEADDED:
+ {
+ // make sure this isn't an event for a reconnected game controller
+ auto const controller = find_joystick(SDL_JoystickGetDeviceInstanceID(sdlevent.jdevice.which));
+ if (find_joystick(SDL_JoystickGetDeviceInstanceID(sdlevent.jdevice.which)))
+ {
+ osd_printf_verbose(
+ "Game Controller: Got SDL joystick added event for reconnected game controller %s [ID %s]\n",
+ controller->name(),
+ controller->id());
+ break;
+ }
- // if we find a matching controller, dispatch the event to the game controller
- if (target_device)
- target_device->queue_events(&sdlevent, 1);
+ SDL_Joystick *const joy = SDL_JoystickOpen(sdlevent.jdevice.which);
+ if (!joy)
+ {
+ osd_printf_error("Joystick: Could not open SDL joystick %d: %s.\n", sdlevent.jdevice.which, SDL_GetError());
+ break;
+ }
+
+ SDL_JoystickGUID guid = SDL_JoystickGetGUID(joy);
+ char const *serial = nullptr;
+#if SDL_VERSION_ATLEAST(2, 0, 14)
+ serial = SDL_JoystickGetSerial(joy);
+#endif
+ auto *const target_device = find_reconnect_match(guid, serial);
+ if (target_device)
+ {
+ // if this downcast fails, opening as a game controller worked initially but failed on reconnection
+ auto *const devinfo = dynamic_cast<sdl_joystick_device *>(target_device);
+ if (devinfo)
+ devinfo->attach_device(joy);
+ else
+ SDL_JoystickClose(joy);
+ }
+ else
+ {
+ SDL_JoystickClose(joy);
+ }
+ }
+ break;
+
+ // for devices supported by the game controller API, this is received before the corresponding SDL_JOYDEVICEADDED
+ case SDL_CONTROLLERDEVICEADDED:
+ {
+ SDL_GameController *const ctrl = SDL_GameControllerOpen(sdlevent.cdevice.which);
+ if (!ctrl)
+ {
+ osd_printf_error("Game Controller: Could not open SDL game controller %d: %s.\n", sdlevent.cdevice.which, SDL_GetError());
+ break;
+ }
+
+ SDL_JoystickGUID guid = SDL_JoystickGetDeviceGUID(sdlevent.cdevice.which);
+ char const *serial = nullptr;
+#if SDL_VERSION_ATLEAST(2, 0, 14)
+ serial = SDL_GameControllerGetSerial(ctrl);
+#endif
+ auto *const target_device = find_reconnect_match(guid, serial);
+ if (target_device)
+ {
+ // downcast can fail if there was an error opening the device as a game controller the first time
+ auto *const devinfo = dynamic_cast<sdl_game_controller_device *>(target_device);
+ if (devinfo)
+ devinfo->attach_device(ctrl);
+ else
+ SDL_GameControllerClose(ctrl);
+ }
+ else
+ {
+ SDL_GameControllerClose(ctrl);
+ }
+ }
+ break;
+
+ default:
+ dispatch_joystick_event(sdlevent);
+ }
}
private:
- sdl_game_controller_device *find_controller(SDL_JoystickID instance)
+ sdl_game_controller_device *create_game_controller_device(running_machine &machine, int index, SDL_GameController *ctrl)
{
- for (auto &ptr : devicelist())
+ // get basic info
+ char const *const name = SDL_GameControllerName(ctrl);
+ SDL_JoystickGUID guid = SDL_JoystickGetDeviceGUID(index);
+ char guid_str[256];
+ guid_str[0] = '\0';
+ SDL_JoystickGetGUIDString(guid, guid_str, sizeof(guid_str) - 1);
+ char const *serial = nullptr;
+#if SDL_VERSION_ATLEAST(2, 0, 14)
+ serial = SDL_GameControllerGetSerial(ctrl);
+#endif
+ std::string id(guid_str);
+ if (serial)
+ id.append(1, '-').append(serial);
+
+ // instantiate device
+ sdl_game_controller_device &devinfo = devicelist().create_device<sdl_game_controller_device>(
+ machine,
+ name ? name : guid_str,
+ guid_str,
+ *this,
+ ctrl,
+ serial);
+
+ // print some diagnostic info
+ osd_printf_verbose("Game Controller: %s [GUID %s] Vendor ID %04X, Product ID %04X, Revision %04X, Serial %s\n",
+ name ? name : "<nullptr>",
+ guid_str,
+ SDL_GameControllerGetVendor(ctrl),
+ SDL_GameControllerGetProduct(ctrl),
+ SDL_GameControllerGetProductVersion(ctrl),
+ serial ? serial : "<nullptr>");
+ char *const mapping = SDL_GameControllerMapping(ctrl);
+ if (mapping)
{
- sdl_game_controller_device *const device = downcast<sdl_game_controller_device *>(ptr.get());
- if (device->is_instance(instance))
- return device;
+ osd_printf_verbose("Game Controller: ... mapping [%s]\n", mapping);
+ SDL_free(mapping);
}
- return nullptr;
+ else
+ {
+ osd_printf_verbose("Game Controller: ... no mapping\n");
+ }
+
+ // let it add controls
+ devinfo.configure();
+ return &devinfo;
}
bool m_initialized_game_controller;