summaryrefslogtreecommitdiffstatshomepage
path: root/src/osd/modules/input/input_sdl.cpp
diff options
context:
space:
mode:
author Vas Crabb <cuavas@users.noreply.github.com>2022-04-24 15:31:45 +1000
committer GitHub <noreply@github.com>2022-04-24 15:31:45 +1000
commit8614b890d377a45a765c2fab3b230512648f8b13 (patch)
tree1536d3e5c83500e5195a27d0545b4cd465a5cc9a /src/osd/modules/input/input_sdl.cpp
parent25c64006b7ca4bbb0d575b46c6c5c4f214dac7ed (diff)
osd/modules/input: Detect joystick reconnection with SDL. (#9605)
Also improved display name scheme for joystick axes and buttons.
Diffstat (limited to 'src/osd/modules/input/input_sdl.cpp')
-rw-r--r--src/osd/modules/input/input_sdl.cpp302
1 files changed, 181 insertions, 121 deletions
diff --git a/src/osd/modules/input/input_sdl.cpp b/src/osd/modules/input/input_sdl.cpp
index 58901627bcf..8937e4cb2a6 100644
--- a/src/osd/modules/input/input_sdl.cpp
+++ b/src/osd/modules/input/input_sdl.cpp
@@ -20,12 +20,13 @@
#include <SDL2/SDL.h>
#include <cctype>
// ReSharper disable once CppUnusedIncludeDirective
+#include <algorithm>
#include <cstddef>
-#include <mutex>
+#include <iterator>
#include <memory>
+#include <mutex>
+#include <optional>
#include <queue>
-#include <iterator>
-#include <algorithm>
// MAME headers
#include "emu.h"
@@ -373,6 +374,14 @@ protected:
class sdl_keyboard_device : public sdl_device
{
public:
+ // state information for a keyboard
+ struct keyboard_state
+ {
+ int32_t state[0x3ff]; // must be int32_t!
+ int8_t oldkey[MAX_KEYS];
+ int8_t currkey[MAX_KEYS];
+ };
+
keyboard_state keyboard;
sdl_keyboard_device(running_machine &machine, std::string &&name, std::string &&id, input_module &module) :
@@ -483,6 +492,13 @@ private:
int last_y;
public:
+ // state information for a mouse
+ struct mouse_state
+ {
+ int32_t lX, lY;
+ int32_t buttons[MAX_BUTTONS];
+ };
+
mouse_state mouse;
sdl_mouse_device(running_machine &machine, std::string &&name, std::string &&id, input_module &module) :
@@ -602,40 +618,40 @@ public:
// sdl_joystick_device
//============================================================
-// state information for a joystick
-struct sdl_joystick_state
-{
- int32_t axes[MAX_AXES];
- int32_t buttons[MAX_BUTTONS];
- int32_t hatsU[MAX_HATS], hatsD[MAX_HATS], hatsL[MAX_HATS], hatsR[MAX_HATS];
- int32_t balls[MAX_AXES];
-};
-
-struct sdl_api_state
-{
- SDL_Joystick *device;
- SDL_Haptic *hapdevice;
- SDL_JoystickID joystick_id;
-};
-
class sdl_joystick_device : public sdl_device
{
public:
+ // state information for a joystick
+ struct sdl_joystick_state
+ {
+ int32_t axes[MAX_AXES];
+ int32_t buttons[MAX_BUTTONS];
+ int32_t hatsU[MAX_HATS], hatsD[MAX_HATS], hatsL[MAX_HATS], hatsR[MAX_HATS];
+ int32_t balls[MAX_AXES];
+ };
+
+ struct sdl_api_state
+ {
+ SDL_Joystick *device = nullptr;
+ SDL_Haptic *hapdevice = nullptr;
+ SDL_JoystickID joystick_id;
+ std::optional<std::string> serial;
+ };
+
sdl_joystick_state joystick;
sdl_api_state sdl_state;
sdl_joystick_device(running_machine &machine, std::string &&name, std::string &&id, input_module &module) :
sdl_device(machine, std::move(name), std::move(id), DEVICE_CLASS_JOYSTICK, module),
- joystick({{0}}),
- sdl_state({ nullptr })
+ joystick({{0}})
{
}
~sdl_joystick_device()
{
- if (sdl_state.device != nullptr)
+ if (sdl_state.device)
{
- if (sdl_state.hapdevice != nullptr)
+ if (sdl_state.hapdevice)
{
SDL_HapticClose(sdl_state.hapdevice);
sdl_state.hapdevice = nullptr;
@@ -665,38 +681,10 @@ public:
break;
case SDL_JOYHATMOTION:
- if (sdlevent.jhat.value & SDL_HAT_UP)
- {
- joystick.hatsU[sdlevent.jhat.hat] = 0x80;
- }
- else
- {
- joystick.hatsU[sdlevent.jhat.hat] = 0;
- }
- if (sdlevent.jhat.value & SDL_HAT_DOWN)
- {
- joystick.hatsD[sdlevent.jhat.hat] = 0x80;
- }
- else
- {
- joystick.hatsD[sdlevent.jhat.hat] = 0;
- }
- if (sdlevent.jhat.value & SDL_HAT_LEFT)
- {
- joystick.hatsL[sdlevent.jhat.hat] = 0x80;
- }
- else
- {
- joystick.hatsL[sdlevent.jhat.hat] = 0;
- }
- if (sdlevent.jhat.value & SDL_HAT_RIGHT)
- {
- joystick.hatsR[sdlevent.jhat.hat] = 0x80;
- }
- else
- {
- joystick.hatsR[sdlevent.jhat.hat] = 0;
- }
+ joystick.hatsU[sdlevent.jhat.hat] = (sdlevent.jhat.value & SDL_HAT_UP) ? 0x80 : 0;
+ joystick.hatsD[sdlevent.jhat.hat] = (sdlevent.jhat.value & SDL_HAT_DOWN) ? 0x80 : 0;
+ joystick.hatsL[sdlevent.jhat.hat] = (sdlevent.jhat.value & SDL_HAT_LEFT) ? 0x80 : 0;
+ joystick.hatsR[sdlevent.jhat.hat] = (sdlevent.jhat.value & SDL_HAT_RIGHT) ? 0x80 : 0;
break;
case SDL_JOYBUTTONDOWN:
@@ -704,6 +692,21 @@ public:
if (sdlevent.jbutton.button < MAX_BUTTONS)
joystick.buttons[sdlevent.jbutton.button] = (sdlevent.jbutton.state == SDL_PRESSED) ? 0x80 : 0;
break;
+
+ case SDL_JOYDEVICEREMOVED:
+ osd_printf_verbose("Joystick: %s [GUID %s] disconnected\n", name(), id());
+ reset();
+ if (sdl_state.device)
+ {
+ if (sdl_state.hapdevice)
+ {
+ SDL_HapticClose(sdl_state.hapdevice);
+ sdl_state.hapdevice = nullptr;
+ }
+ SDL_JoystickClose(sdl_state.device);
+ sdl_state.device = nullptr;
+ }
+ break;
}
}
};
@@ -786,9 +789,10 @@ public:
void handle_event(SDL_Event &sdlevent) override
{
// By default dispatch event to every device
- devicelist()->for_each_device([&sdlevent](auto device) {
- downcast<sdl_device*>(device)->queue_events(&sdlevent, 1);
- });
+ devicelist().for_each_device(
+ [&sdlevent](auto device) {
+ downcast<sdl_device*>(device)->queue_events(&sdlevent, 1);
+ });
}
};
@@ -810,13 +814,12 @@ public:
{
sdl_input_module::input_init(machine);
- static int event_types[] = {
- static_cast<int>(SDL_KEYDOWN),
- static_cast<int>(SDL_KEYUP),
- static_cast<int>(SDL_TEXTINPUT)
- };
+ static int const event_types[] = {
+ int(SDL_KEYDOWN),
+ int(SDL_KEYUP),
+ int(SDL_TEXTINPUT) };
- sdl_event_manager::instance().subscribe(event_types, std::size(event_types), this);
+ sdl_event_manager::instance().subscribe(event_types, this);
// Read our keymap and store a pointer to our table
m_key_trans_table = sdlinput_read_keymap(machine);
@@ -826,7 +829,7 @@ public:
osd_printf_verbose("Keyboard: Start initialization\n");
// SDL only has 1 keyboard add it now
- auto &devinfo = devicelist()->create_device<sdl_keyboard_device>(machine, "System keyboard", "System keyboard", *this);
+ auto &devinfo = devicelist().create_device<sdl_keyboard_device>(machine, "System keyboard", "System keyboard", *this);
// populate it
for (int keynum = 0; local_table[keynum].mame_key != ITEM_ID_INVALID; keynum++)
@@ -942,19 +945,18 @@ public:
{
sdl_input_module::input_init(machine);
- static int event_types[] = {
- static_cast<int>(SDL_MOUSEMOTION),
- static_cast<int>(SDL_MOUSEBUTTONDOWN),
- static_cast<int>(SDL_MOUSEBUTTONUP),
- static_cast<int>(SDL_MOUSEWHEEL)
- };
+ static int const event_types[] = {
+ int(SDL_MOUSEMOTION),
+ int(SDL_MOUSEBUTTONDOWN),
+ int(SDL_MOUSEBUTTONUP),
+ int(SDL_MOUSEWHEEL) };
- sdl_event_manager::instance().subscribe(event_types, std::size(event_types), this);
+ sdl_event_manager::instance().subscribe(event_types, this);
osd_printf_verbose("Mouse: Start initialization\n");
// SDL currently only supports one mouse
- auto &devinfo = devicelist()->create_device<sdl_mouse_device>(machine, "System mouse", "System mouse", *this);
+ auto &devinfo = devicelist().create_device<sdl_mouse_device>(machine, "System mouse", "System mouse", *this);
// add the axes
devinfo.device()->add_item("X", ITEM_ID_XAXIS, generic_axis_get_state<std::int32_t>, &devinfo.mouse.lX);
@@ -981,12 +983,15 @@ void devmap_register(device_map_t &devmap, int physical_idx, const std::string &
auto entry = std::find_if(
std::begin(devmap.map),
std::end(devmap.map),
- [&name] (auto &item) { return (item.name == name) && (item.physical < 0); });
+ [&name] (auto const &item) { return (item.name == name) && (item.physical < 0); });
// If we didn't find it by name, find the first free slot
if (entry == std::end(devmap.map))
{
- entry = std::find_if(std::begin(devmap.map), std::end(devmap.map), [] (auto &item) { return item.name.empty(); });
+ entry = std::find_if(
+ std::begin(devmap.map),
+ std::end(devmap.map),
+ [] (auto const &item) { return item.name.empty(); });
}
if (entry != std::end(devmap.map))
@@ -1054,13 +1059,12 @@ public:
char tempname[512];
- m_sixaxis_mode = downcast<const sdl_options*>(options())->sixaxis();
+ m_sixaxis_mode = downcast<const sdl_options *>(options())->sixaxis();
devmap_init(machine, &m_joy_map, SDLOPTION_JOYINDEX, 8, "Joystick mapping");
osd_printf_verbose("Joystick: Start initialization\n");
- int physical_stick;
- for (physical_stick = 0; physical_stick < SDL_NumJoysticks(); physical_stick++)
+ for (int physical_stick = 0; physical_stick < SDL_NumJoysticks(); physical_stick++)
{
std::string joy_name = remove_spaces(SDL_JoystickNameForIndex(physical_stick));
devmap_register(m_joy_map, physical_stick, joy_name);
@@ -1073,28 +1077,40 @@ public:
if (!devinfo)
continue;
- physical_stick = m_joy_map.map[stick].physical;
- SDL_Joystick *joy = SDL_JoystickOpen(physical_stick);
+ int const physical_stick = m_joy_map.map[stick].physical;
+ SDL_Joystick *const joy = SDL_JoystickOpen(physical_stick);
SDL_JoystickGUID guid = SDL_JoystickGetGUID(joy);
char guid_str[256];
guid_str[0] = '\0';
- SDL_JoystickGetGUIDString(guid, guid_str, sizeof(guid_str)-1);
+ SDL_JoystickGetGUIDString(guid, guid_str, sizeof(guid_str) - 1);
devinfo->sdl_state.device = joy;
devinfo->sdl_state.joystick_id = SDL_JoystickInstanceID(joy);
devinfo->sdl_state.hapdevice = SDL_HapticOpenFromJoystick(joy);
-
- osd_printf_verbose("Joystick: %s [GUID %s]\n", SDL_JoystickNameForIndex(physical_stick), guid_str);
- 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 SDL_VERSION_ATLEAST(2, 0, 14)
+ char const *const serial = SDL_JoystickGetSerial(joy);
+ if (serial)
+ devinfo->sdl_state.serial = serial;
+ else
+#endif // SDL_VERSION_ATLEAST(2, 0, 14)
+ devinfo->sdl_state.serial = std::nullopt;
+
+ osd_printf_verbose("Joystick: %s [GUID %s] Vendor ID %04X, Product ID %04X, Revision %04X\n",
+ SDL_JoystickNameForIndex(physical_stick),
+ guid_str,
+ SDL_JoystickGetVendor(joy),
+ SDL_JoystickGetProduct(joy),
+ SDL_JoystickGetProductVersion(joy));
+ 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));
osd_printf_verbose("Joystick: ... Physical id %d mapped to logical id %d\n", physical_stick, stick + 1);
- if (devinfo->sdl_state.hapdevice != nullptr)
- {
+ if (devinfo->sdl_state.hapdevice)
osd_printf_verbose("Joystick: ... Has haptic capability\n");
- }
else
- {
osd_printf_verbose("Joystick: ... Does not have haptic capability\n");
- }
// loop over all axes
for (int axis = 0; axis < SDL_JoystickNumAxes(joy); axis++)
@@ -1108,7 +1124,7 @@ public:
else
itemid = ITEM_ID_OTHER_AXIS_ABSOLUTE;
- snprintf(tempname, sizeof(tempname), "A%d %s", axis, devinfo->name().c_str());
+ snprintf(tempname, sizeof(tempname), "A%d", axis + 1);
devinfo->device()->add_item(tempname, itemid, generic_axis_get_state<std::int32_t>, &devinfo->joystick.axes[axis]);
}
@@ -1128,7 +1144,7 @@ public:
else
itemid = ITEM_ID_OTHER_SWITCH;
- snprintf(tempname, sizeof(tempname), "button %d", button);
+ snprintf(tempname, sizeof(tempname), "Button %d", button + 1);
devinfo->device()->add_item(tempname, itemid, generic_button_get_state<std::int32_t>, &devinfo->joystick.buttons[button]);
}
@@ -1137,16 +1153,16 @@ public:
{
input_item_id itemid;
- snprintf(tempname, sizeof(tempname), "hat %d Up", hat);
+ snprintf(tempname, sizeof(tempname), "Hat %d Up", hat + 1);
itemid = (input_item_id)((hat < INPUT_MAX_HATS) ? ITEM_ID_HAT1UP + 4 * hat : ITEM_ID_OTHER_SWITCH);
devinfo->device()->add_item(tempname, itemid, generic_button_get_state<std::int32_t>, &devinfo->joystick.hatsU[hat]);
- snprintf(tempname, sizeof(tempname), "hat %d Down", hat);
+ snprintf(tempname, sizeof(tempname), "Hat %d Down", hat + 1);
itemid = (input_item_id)((hat < INPUT_MAX_HATS) ? ITEM_ID_HAT1DOWN + 4 * hat : ITEM_ID_OTHER_SWITCH);
devinfo->device()->add_item(tempname, itemid, generic_button_get_state<std::int32_t>, &devinfo->joystick.hatsD[hat]);
- snprintf(tempname, sizeof(tempname), "hat %d Left", hat);
+ snprintf(tempname, sizeof(tempname), "Hat %d Left", hat + 1);
itemid = (input_item_id)((hat < INPUT_MAX_HATS) ? ITEM_ID_HAT1LEFT + 4 * hat : ITEM_ID_OTHER_SWITCH);
devinfo->device()->add_item(tempname, itemid, generic_button_get_state<std::int32_t>, &devinfo->joystick.hatsL[hat]);
- snprintf(tempname, sizeof(tempname), "hat %d Right", hat);
+ snprintf(tempname, sizeof(tempname), "Hat %d Right", hat + 1);
itemid = (input_item_id)((hat < INPUT_MAX_HATS) ? ITEM_ID_HAT1RIGHT + 4 * hat : ITEM_ID_OTHER_SWITCH);
devinfo->device()->add_item(tempname, itemid, generic_button_get_state<std::int32_t>, &devinfo->joystick.hatsR[hat]);
}
@@ -1161,46 +1177,90 @@ public:
else
itemid = ITEM_ID_OTHER_AXIS_RELATIVE;
- snprintf(tempname, sizeof(tempname), "R%d %s", ball * 2, devinfo->name().c_str());
+ snprintf(tempname, sizeof(tempname), "R%d X", ball + 1);
devinfo->device()->add_item(tempname, (input_item_id)itemid, generic_axis_get_state<std::int32_t>, &devinfo->joystick.balls[ball * 2]);
- snprintf(tempname, sizeof(tempname), "R%d %s", ball * 2 + 1, devinfo->name().c_str());
+ snprintf(tempname, sizeof(tempname), "R%d Y", ball + 1);
devinfo->device()->add_item(tempname, (input_item_id)(itemid + 1), generic_axis_get_state<std::int32_t>, &devinfo->joystick.balls[ball * 2 + 1]);
}
}
- static int event_types[] = {
- static_cast<int>(SDL_JOYAXISMOTION),
- static_cast<int>(SDL_JOYBALLMOTION),
- static_cast<int>(SDL_JOYHATMOTION),
- static_cast<int>(SDL_JOYBUTTONDOWN),
- static_cast<int>(SDL_JOYBUTTONUP)
- };
+ 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) };
- sdl_event_manager::instance().subscribe(event_types, std::size(event_types), this);
+ sdl_event_manager::instance().subscribe(event_types, this);
osd_printf_verbose("Joystick: End initialization\n");
}
virtual void handle_event(SDL_Event &sdlevent) override
{
- // Figure out which joystick this event id destined for
- auto target_device = std::find_if(
- devicelist()->begin(),
- devicelist()->end(),
- [&sdlevent] (auto &device)
+ if (SDL_JOYDEVICEADDED == sdlevent.type)
+ {
+ SDL_Joystick *const joy = SDL_JoystickOpen(sdlevent.jdevice.which);
+ if (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
+ 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.sdl_state.device &&
+ (devinfo.id() == guid_str) &&
+ ((serial && devinfo.sdl_state.serial && (*devinfo.sdl_state.serial == serial)) || (!serial && !devinfo.sdl_state.serial));
+ });
+ if (devicelist().end() != target_device)
{
- std::unique_ptr<device_info> &ptr = device;
- return downcast<sdl_joystick_device*>(ptr.get())->sdl_state.joystick_id == sdlevent.jdevice.which;
- });
-
- // If we find a matching joystick, dispatch the event to the joystick
- if (target_device != devicelist()->end())
+ auto &devinfo = downcast<sdl_joystick_device &>(**target_device);
+ devinfo.sdl_state.device = joy;
+ devinfo.sdl_state.joystick_id = SDL_JoystickInstanceID(joy);
+ devinfo.sdl_state.hapdevice = SDL_HapticOpenFromJoystick(joy);
+ osd_printf_verbose("Joystick: %s [GUID %s] reconnected\n", devinfo.name(), guid_str);
+ }
+ else
+ {
+ SDL_JoystickClose(joy);
+ }
+ }
+ }
+ else
{
- downcast<sdl_joystick_device*>((*target_device).get())->queue_events(&sdlevent, 1);
+ // Figure out which joystick this event id 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->sdl_state.device && (device->sdl_state.joystick_id == instance))
+ return device;
+ }
+ return nullptr;
+ }
+
sdl_joystick_device *create_joystick_device(running_machine &machine, device_map_t *devmap, int index, input_device_class devclass)
{
char tempname[20];
@@ -1215,16 +1275,16 @@ private:
{
snprintf(tempname, std::size(tempname), "NC%d", index);
m_sixaxis_mode
- ? devicelist()->create_device<sdl_sixaxis_joystick_device>(machine, tempname, guid_str, *this)
- : devicelist()->create_device<sdl_joystick_device>(machine, tempname, guid_str, *this);
+ ? devicelist().create_device<sdl_sixaxis_joystick_device>(machine, tempname, guid_str, *this)
+ : devicelist().create_device<sdl_joystick_device>(machine, tempname, guid_str, *this);
}
return nullptr;
}
return m_sixaxis_mode
- ? &devicelist()->create_device<sdl_sixaxis_joystick_device>(machine, std::string(devmap->map[index].name), guid_str, *this)
- : &devicelist()->create_device<sdl_joystick_device>(machine, std::string(devmap->map[index].name), guid_str, *this);
+ ? &devicelist().create_device<sdl_sixaxis_joystick_device>(machine, std::string(devmap->map[index].name), guid_str, *this)
+ : &devicelist().create_device<sdl_joystick_device>(machine, std::string(devmap->map[index].name), guid_str, *this);
}
};