mirror of
https://github.com/holub/mame
synced 2025-07-01 08:18:59 +03:00
-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.
This commit is contained in:
parent
58f41bfa47
commit
e817a3d0c8
@ -214,6 +214,29 @@ char const *const CONTROLLER_BUTTON_XBOX360[]{
|
|||||||
"P4",
|
"P4",
|
||||||
"Touchpad" };
|
"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
|
struct key_lookup_table
|
||||||
{
|
{
|
||||||
int code;
|
int code;
|
||||||
@ -785,6 +808,14 @@ public:
|
|||||||
|
|
||||||
bool is_instance(SDL_JoystickID instance) const { return m_instance == instance; }
|
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:
|
protected:
|
||||||
sdl_joystick_device_base(
|
sdl_joystick_device_base(
|
||||||
running_machine &machine,
|
running_machine &machine,
|
||||||
@ -1006,7 +1037,7 @@ public:
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case SDL_JOYDEVICEREMOVED:
|
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();
|
clear_instance();
|
||||||
reset();
|
reset();
|
||||||
if (m_joydevice)
|
if (m_joydevice)
|
||||||
@ -1028,14 +1059,6 @@ public:
|
|||||||
return m_hapdevice != nullptr;
|
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)
|
void attach_device(SDL_Joystick *joy)
|
||||||
{
|
{
|
||||||
assert(joy);
|
assert(joy);
|
||||||
@ -1044,6 +1067,8 @@ public:
|
|||||||
set_instance(SDL_JoystickInstanceID(joy));
|
set_instance(SDL_JoystickInstanceID(joy));
|
||||||
m_joydevice = joy;
|
m_joydevice = joy;
|
||||||
m_hapdevice = SDL_HapticOpenFromJoystick(joy);
|
m_hapdevice = SDL_HapticOpenFromJoystick(joy);
|
||||||
|
|
||||||
|
osd_printf_verbose("Joystick: %s [ID %s] reconnected\n", name(), id());
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
@ -1138,6 +1163,7 @@ public:
|
|||||||
{
|
{
|
||||||
char const *const *axisnames = CONTROLLER_AXIS_XBOX;
|
char const *const *axisnames = CONTROLLER_AXIS_XBOX;
|
||||||
char const *const *buttonnames = CONTROLLER_BUTTON_XBOX360;
|
char const *const *buttonnames = CONTROLLER_BUTTON_XBOX360;
|
||||||
|
bool digitaltriggers = false;
|
||||||
#if SDL_VERSION_ATLEAST(2, 0, 12)
|
#if SDL_VERSION_ATLEAST(2, 0, 12)
|
||||||
auto const ctrltype = SDL_GameControllerGetType(m_ctrldevice);
|
auto const ctrltype = SDL_GameControllerGetType(m_ctrldevice);
|
||||||
switch (ctrltype)
|
switch (ctrltype)
|
||||||
@ -1169,6 +1195,7 @@ public:
|
|||||||
osd_printf_verbose("Game Controller: ... Switch Pro Controller type\n");
|
osd_printf_verbose("Game Controller: ... Switch Pro Controller type\n");
|
||||||
axisnames = CONTROLLER_AXIS_SWITCH;
|
axisnames = CONTROLLER_AXIS_SWITCH;
|
||||||
buttonnames = CONTROLLER_BUTTON_SWITCH;
|
buttonnames = CONTROLLER_BUTTON_SWITCH;
|
||||||
|
digitaltriggers = true;
|
||||||
break;
|
break;
|
||||||
#if SDL_VERSION_ATLEAST(2, 0, 14) // TODO: support more controller types
|
#if SDL_VERSION_ATLEAST(2, 0, 14) // TODO: support more controller types
|
||||||
//case SDL_CONTROLLER_TYPE_VIRTUAL:
|
//case SDL_CONTROLLER_TYPE_VIRTUAL:
|
||||||
@ -1178,13 +1205,17 @@ public:
|
|||||||
buttonnames = CONTROLLER_BUTTON_PS5;
|
buttonnames = CONTROLLER_BUTTON_PS5;
|
||||||
break;
|
break;
|
||||||
//case SDL_CONTROLLER_TYPE_AMAZON_LUNA:
|
//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_LEFT:
|
||||||
//case SDL_CONTROLLER_TYPE_SWITCH_JOYCON_RIGHT:
|
//case SDL_CONTROLLER_TYPE_SWITCH_JOYCON_RIGHT:
|
||||||
//case SDL_CONTROLLER_TYPE_SWITCH_JOYCON_PAIR:
|
//case SDL_CONTROLLER_TYPE_SWITCH_JOYCON_PAIR:
|
||||||
#endif
|
#endif
|
||||||
default: // default to Xbox 360 names
|
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;
|
break;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@ -1199,9 +1230,9 @@ public:
|
|||||||
{ SDL_CONTROLLER_AXIS_TRIGGERRIGHT, ITEM_ID_SLIDER2, true } };
|
{ SDL_CONTROLLER_AXIS_TRIGGERRIGHT, ITEM_ID_SLIDER2, true } };
|
||||||
for (auto [axis, item, buttontest] : axes)
|
for (auto [axis, item, buttontest] : axes)
|
||||||
{
|
{
|
||||||
bool avail = true;
|
bool avail = !buttontest || !digitaltriggers;
|
||||||
#if SDL_VERSION_ATLEAST(2, 0, 14)
|
#if SDL_VERSION_ATLEAST(2, 0, 14)
|
||||||
avail = SDL_GameControllerHasAxis(m_ctrldevice, axis);
|
avail = avail && SDL_GameControllerHasAxis(m_ctrldevice, axis);
|
||||||
#endif
|
#endif
|
||||||
if (avail)
|
if (avail)
|
||||||
{
|
{
|
||||||
@ -1293,10 +1324,13 @@ public:
|
|||||||
auto const binding = SDL_GameControllerGetBindForAxis(m_ctrldevice, axis);
|
auto const binding = SDL_GameControllerGetBindForAxis(m_ctrldevice, axis);
|
||||||
switch (binding.bindType)
|
switch (binding.bindType)
|
||||||
{
|
{
|
||||||
|
case SDL_CONTROLLER_BINDTYPE_NONE:
|
||||||
|
avail = false;
|
||||||
|
break;
|
||||||
case SDL_CONTROLLER_BINDTYPE_BUTTON:
|
case SDL_CONTROLLER_BINDTYPE_BUTTON:
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
avail = false;
|
avail = digitaltriggers;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (avail)
|
if (avail)
|
||||||
@ -1381,7 +1415,7 @@ public:
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case SDL_CONTROLLERDEVICEREMOVED:
|
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();
|
clear_instance();
|
||||||
reset();
|
reset();
|
||||||
if (m_ctrldevice)
|
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:
|
private:
|
||||||
// state information for a game controller
|
// state information for a game controller
|
||||||
struct sdl_controller_state
|
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:
|
protected:
|
||||||
sdl_joystick_module() :
|
sdl_joystick_module_base(char const *name) :
|
||||||
sdl_input_module(OSD_JOYSTICKINPUT_PROVIDER, "sdljoy"),
|
sdl_input_module(OSD_JOYSTICKINPUT_PROVIDER, name),
|
||||||
m_initialized_joystick(false),
|
m_initialized_joystick(false),
|
||||||
m_initialized_haptic(false)
|
m_initialized_haptic(false)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void exit() override
|
virtual ~sdl_joystick_module_base()
|
||||||
{
|
{
|
||||||
sdl_input_module::exit();
|
assert(!m_initialized_joystick);
|
||||||
|
assert(!m_initialized_haptic);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool have_joystick() const { return m_initialized_joystick; }
|
||||||
|
bool have_haptic() const { return m_initialized_haptic; }
|
||||||
|
|
||||||
|
void init_joystick()
|
||||||
|
{
|
||||||
|
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 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());
|
||||||
|
}
|
||||||
|
|
||||||
|
void quit_joystick()
|
||||||
|
{
|
||||||
if (m_initialized_joystick)
|
if (m_initialized_joystick)
|
||||||
|
{
|
||||||
SDL_QuitSubSystem(SDL_INIT_JOYSTICK);
|
SDL_QuitSubSystem(SDL_INIT_JOYSTICK);
|
||||||
|
m_initialized_joystick = false;
|
||||||
|
}
|
||||||
|
|
||||||
if (m_initialized_haptic)
|
if (m_initialized_haptic)
|
||||||
|
{
|
||||||
SDL_QuitSubSystem(SDL_INIT_HAPTIC);
|
SDL_QuitSubSystem(SDL_INIT_HAPTIC);
|
||||||
|
m_initialized_haptic = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
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);
|
||||||
|
#endif
|
||||||
|
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);
|
||||||
|
|
||||||
|
// let it add controls
|
||||||
|
devinfo.configure();
|
||||||
|
return &devinfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
// 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
virtual void input_init(running_machine &machine) override
|
||||||
{
|
{
|
||||||
SDL_SetHint(SDL_HINT_ACCELEROMETER_AS_JOYSTICK, "0");
|
SDL_SetHint(SDL_HINT_ACCELEROMETER_AS_JOYSTICK, "0");
|
||||||
|
|
||||||
m_initialized_joystick = !SDL_InitSubSystem(SDL_INIT_JOYSTICK);
|
init_joystick();
|
||||||
if (!m_initialized_joystick)
|
if (!have_joystick())
|
||||||
{
|
|
||||||
osd_printf_error("Could not initialize SDL Joystick: %s.\n", SDL_GetError());
|
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
|
|
||||||
m_initialized_haptic = !SDL_InitSubSystem(SDL_INIT_HAPTIC);
|
sdl_joystick_module_base::input_init(machine);
|
||||||
if (!m_initialized_haptic)
|
|
||||||
{
|
|
||||||
osd_printf_verbose("Could not initialize SDL Haptic subsystem: %s.\n", SDL_GetError());
|
|
||||||
}
|
|
||||||
|
|
||||||
sdl_input_module::input_init(machine);
|
|
||||||
|
|
||||||
bool const sixaxis_mode = downcast<const sdl_options *>(options())->sixaxis();
|
bool const sixaxis_mode = downcast<const sdl_options *>(options())->sixaxis();
|
||||||
|
|
||||||
osd_printf_verbose("Joystick: Start initialization\n");
|
osd_printf_verbose("Joystick: Start initialization\n");
|
||||||
for (int physical_stick = 0; physical_stick < SDL_NumJoysticks(); physical_stick++)
|
for (int physical_stick = 0; physical_stick < SDL_NumJoysticks(); physical_stick++)
|
||||||
{
|
create_joystick_device(machine, physical_stick, sixaxis_mode);
|
||||||
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;
|
|
||||||
#if SDL_VERSION_ATLEAST(2, 0, 14)
|
|
||||||
serial = SDL_JoystickGetSerial(joy);
|
|
||||||
#endif
|
|
||||||
std::string id(guid_str);
|
|
||||||
if (serial)
|
|
||||||
id.append(1, '-').append(serial);
|
|
||||||
|
|
||||||
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);
|
|
||||||
|
|
||||||
if (!devinfo)
|
|
||||||
{
|
|
||||||
SDL_JoystickClose(joy);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
|
||||||
|
|
||||||
devinfo->configure();
|
|
||||||
}
|
|
||||||
|
|
||||||
static int const event_types[] = {
|
static int const event_types[] = {
|
||||||
int(SDL_JOYAXISMOTION),
|
int(SDL_JOYAXISMOTION),
|
||||||
@ -1735,7 +1871,6 @@ public:
|
|||||||
int(SDL_JOYBUTTONUP),
|
int(SDL_JOYBUTTONUP),
|
||||||
int(SDL_JOYDEVICEADDED),
|
int(SDL_JOYDEVICEADDED),
|
||||||
int(SDL_JOYDEVICEREMOVED) };
|
int(SDL_JOYDEVICEREMOVED) };
|
||||||
|
|
||||||
sdl_event_manager::instance().subscribe(event_types, this);
|
sdl_event_manager::instance().subscribe(event_types, this);
|
||||||
|
|
||||||
osd_printf_verbose("Joystick: End initialization\n");
|
osd_printf_verbose("Joystick: End initialization\n");
|
||||||
@ -1746,29 +1881,22 @@ public:
|
|||||||
if (SDL_JOYDEVICEADDED == sdlevent.type)
|
if (SDL_JOYDEVICEADDED == sdlevent.type)
|
||||||
{
|
{
|
||||||
SDL_Joystick *const joy = SDL_JoystickOpen(sdlevent.jdevice.which);
|
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);
|
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;
|
char const *serial = nullptr;
|
||||||
#if SDL_VERSION_ATLEAST(2, 0, 14)
|
#if SDL_VERSION_ATLEAST(2, 0, 14)
|
||||||
serial = SDL_JoystickGetSerial(joy);
|
serial = SDL_JoystickGetSerial(joy);
|
||||||
#endif
|
#endif
|
||||||
auto target_device = std::find_if(
|
auto *const target_device = find_reconnect_match(guid, serial);
|
||||||
devicelist().begin(),
|
if (target_device)
|
||||||
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 &devinfo = downcast<sdl_joystick_device &>(**target_device);
|
auto &devinfo = downcast<sdl_joystick_device &>(*target_device);
|
||||||
devinfo.attach_device(joy);
|
devinfo.attach_device(joy);
|
||||||
osd_printf_verbose("Joystick: %s [GUID %s] reconnected\n", devinfo.name(), guid_str);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -1778,29 +1906,9 @@ public:
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// figure out which joystick this event is destined for
|
dispatch_joystick_event(sdlevent);
|
||||||
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;
|
|
||||||
}
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool m_initialized_joystick;
|
|
||||||
bool m_initialized_haptic;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -1808,11 +1916,11 @@ private:
|
|||||||
// sdl_game_controller_module
|
// sdl_game_controller_module
|
||||||
//============================================================
|
//============================================================
|
||||||
|
|
||||||
class sdl_game_controller_module : public sdl_input_module
|
class sdl_game_controller_module : public sdl_joystick_module_base
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
sdl_game_controller_module() :
|
sdl_game_controller_module() :
|
||||||
sdl_input_module(OSD_JOYSTICKINPUT_PROVIDER, "sdlgame"),
|
sdl_joystick_module_base("sdlgame"),
|
||||||
m_initialized_game_controller(false)
|
m_initialized_game_controller(false)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
@ -1823,80 +1931,58 @@ public:
|
|||||||
|
|
||||||
if (m_initialized_game_controller)
|
if (m_initialized_game_controller)
|
||||||
SDL_QuitSubSystem(SDL_INIT_GAMECONTROLLER);
|
SDL_QuitSubSystem(SDL_INIT_GAMECONTROLLER);
|
||||||
|
|
||||||
|
quit_joystick();
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual void input_init(running_machine &machine) override
|
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);
|
m_initialized_game_controller = !SDL_InitSubSystem(SDL_INIT_GAMECONTROLLER);
|
||||||
if (!m_initialized_game_controller)
|
if (!m_initialized_game_controller)
|
||||||
{
|
osd_printf_warning("Could not initialize SDL Game Controller: %s.\n", SDL_GetError());
|
||||||
osd_printf_error("Could not initialize SDL Game Controller: %s.\n", SDL_GetError());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
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");
|
osd_printf_verbose("Game Controller: Start initialization\n");
|
||||||
for (int physical_stick = 0; physical_stick < SDL_NumJoysticks(); physical_stick++)
|
for (int physical_stick = 0; physical_stick < SDL_NumJoysticks(); physical_stick++)
|
||||||
{
|
{
|
||||||
if (!SDL_IsGameController(physical_stick))
|
// try to open as a game controller
|
||||||
continue;
|
SDL_GameController *ctrl = nullptr;
|
||||||
|
if (m_initialized_game_controller && SDL_IsGameController(physical_stick))
|
||||||
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)
|
|
||||||
{
|
{
|
||||||
SDL_GameControllerClose(ctrl);
|
ctrl = SDL_GameControllerOpen(physical_stick);
|
||||||
continue;
|
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",
|
// fall back to joystick API if necessary
|
||||||
name ? name : "<nullptr>",
|
if (!ctrl)
|
||||||
guid_str,
|
create_joystick_device(machine, physical_stick, sixaxis_mode);
|
||||||
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);
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
create_game_controller_device(machine, physical_stick, ctrl);
|
||||||
osd_printf_verbose("Game Controller: ... no mapping\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
devinfo->configure();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int const event_types[] = {
|
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_CONTROLLERAXISMOTION),
|
||||||
int(SDL_CONTROLLERBUTTONDOWN),
|
int(SDL_CONTROLLERBUTTONDOWN),
|
||||||
int(SDL_CONTROLLERBUTTONUP),
|
int(SDL_CONTROLLERBUTTONUP),
|
||||||
|
int(SDL_CONTROLLERDEVICEADDED),
|
||||||
int(SDL_CONTROLLERDEVICEREMOVED) };
|
int(SDL_CONTROLLERDEVICEREMOVED) };
|
||||||
|
|
||||||
sdl_event_manager::instance().subscribe(event_types, this);
|
sdl_event_manager::instance().subscribe(event_types, this);
|
||||||
|
|
||||||
osd_printf_verbose("Game Controller: End initialization\n");
|
osd_printf_verbose("Game Controller: End initialization\n");
|
||||||
@ -1904,24 +1990,135 @@ public:
|
|||||||
|
|
||||||
virtual void handle_event(SDL_Event &sdlevent) override
|
virtual void handle_event(SDL_Event &sdlevent) override
|
||||||
{
|
{
|
||||||
// figure out which game controller this event is destined for
|
switch (sdlevent.type)
|
||||||
sdl_game_controller_device *const target_device = find_controller(sdlevent.jdevice.which); // FIXME: this depends on SDL_JoystickID being the same size as Sint32
|
{
|
||||||
|
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
|
SDL_Joystick *const joy = SDL_JoystickOpen(sdlevent.jdevice.which);
|
||||||
if (target_device)
|
if (!joy)
|
||||||
target_device->queue_events(&sdlevent, 1);
|
{
|
||||||
|
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:
|
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());
|
osd_printf_verbose("Game Controller: ... mapping [%s]\n", mapping);
|
||||||
if (device->is_instance(instance))
|
SDL_free(mapping);
|
||||||
return device;
|
|
||||||
}
|
}
|
||||||
return nullptr;
|
else
|
||||||
|
{
|
||||||
|
osd_printf_verbose("Game Controller: ... no mapping\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
// let it add controls
|
||||||
|
devinfo.configure();
|
||||||
|
return &devinfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool m_initialized_game_controller;
|
bool m_initialized_game_controller;
|
||||||
|
@ -218,7 +218,7 @@ std::error_condition osd_set_clipboard_text(std::string_view text) noexcept
|
|||||||
GlobalFree(clip);
|
GlobalFree(clip);
|
||||||
return win_error_to_error_condition(err);
|
return win_error_to_error_condition(err);
|
||||||
}
|
}
|
||||||
if (!OpenClipboard(nullptr))
|
if (!EmptyClipboard())
|
||||||
{
|
{
|
||||||
DWORD const err(GetLastError());
|
DWORD const err(GetLastError());
|
||||||
CloseClipboard();
|
CloseClipboard();
|
||||||
|
Loading…
Reference in New Issue
Block a user