summaryrefslogtreecommitdiffstatshomepage
path: root/src/osd/modules/input/input_sdl.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/osd/modules/input/input_sdl.cpp')
-rw-r--r--src/osd/modules/input/input_sdl.cpp2751
1 files changed, 2224 insertions, 527 deletions
diff --git a/src/osd/modules/input/input_sdl.cpp b/src/osd/modules/input/input_sdl.cpp
index 40fe037f8c7..f1fb0241b40 100644
--- a/src/osd/modules/input/input_sdl.cpp
+++ b/src/osd/modules/input/input_sdl.cpp
@@ -1,5 +1,5 @@
// license:BSD-3-Clause
-// copyright-holders:Olivier Galibert, R. Belmont, Brad Hughes
+// copyright-holders:Olivier Galibert, R. Belmont, Brad Hughes, Vas Crabb
//============================================================
//
// input_sdl.cpp - SDL 2.0 implementation of MAME input routines
@@ -12,32 +12,39 @@
//============================================================
#include "input_module.h"
+
#include "modules/osdmodule.h"
-#if defined(SDLMAME_SDL2)
+#if defined(OSD_SDL)
-// standard sdl header
-#include <SDL2/SDL.h>
-#include <ctype.h>
-// ReSharper disable once CppUnusedIncludeDirective
-#include <stddef.h>
-#include <mutex>
-#include <memory>
-#include <queue>
-#include <iterator>
-#include <algorithm>
+#include "assignmenthelper.h"
+#include "input_common.h"
-// MAME headers
-#include "emu.h"
-#include "uiinput.h"
-#include "strconv.h"
+#include "interface/inputseq.h"
+#include "modules/lib/osdobj_common.h"
+#include "sdl/osdsdl.h"
-// MAMEOS headers
-#include "input_common.h"
-#include "../lib/osdobj_common.h"
-#include "input_sdlcommon.h"
-#include "../../sdl/osdsdl.h"
-#include "../../sdl/window.h"
+// emu
+#include "inpttype.h"
+
+// standard SDL header
+#include <SDL2/SDL.h>
+
+#include <algorithm>
+#include <cctype>
+#include <chrono>
+#include <cmath>
+#include <cstddef>
+#include <cstring>
+#include <initializer_list>
+#include <iterator>
+#include <list>
+#include <memory>
+#include <optional>
+#include <string>
+#include <string_view>
+#include <tuple>
+#include <utility>
// winnt.h defines this
#ifdef DELETE
@@ -45,9 +52,217 @@
#endif
-// FIXME: sdl does not properly report the window for certain OS.
-#define GET_FOCUS_WINDOW(ev) focus_window()
-//#define GET_FOCUS_WINDOW(ev) window_from_id((ev)->windowID)
+namespace osd {
+
+namespace {
+
+char const *const CONTROLLER_AXIS_XBOX[]{
+ "LSX",
+ "LSY",
+ "RSX",
+ "RSY",
+ "LT",
+ "RT" };
+
+char const *const CONTROLLER_AXIS_PS[]{
+ "LSX",
+ "LSY",
+ "RSX",
+ "RSY",
+ "L2",
+ "R2" };
+
+char const *const CONTROLLER_AXIS_SWITCH[]{
+ "LSX",
+ "LSY",
+ "RSX",
+ "RSY",
+ "ZL",
+ "ZR" };
+
+char const *const CONTROLLER_BUTTON_XBOX360[]{
+ "A",
+ "B",
+ "X",
+ "Y",
+ "Back",
+ "Guide",
+ "Start",
+ "LSB",
+ "RSB",
+ "LB",
+ "RB",
+ "D-pad Up",
+ "D-pad Down",
+ "D-pad Left",
+ "D-pad Right",
+ "Share",
+ "P1",
+ "P2",
+ "P3",
+ "P4",
+ "Touchpad" };
+
+char const *const CONTROLLER_BUTTON_XBOXONE[]{
+ "A",
+ "B",
+ "X",
+ "Y",
+ "View",
+ "Logo",
+ "Menu",
+ "LSB",
+ "RSB",
+ "LB",
+ "RB",
+ "D-pad Up",
+ "D-pad Down",
+ "D-pad Left",
+ "D-pad Right",
+ "Share",
+ "P1",
+ "P2",
+ "P3",
+ "P4",
+ "Touchpad" };
+
+char const *const CONTROLLER_BUTTON_PS3[]{
+ "Cross",
+ "Circle",
+ "Square",
+ "Triangle",
+ "Select",
+ "PS",
+ "Start",
+ "L3",
+ "R3",
+ "L1",
+ "R1",
+ "D-pad Up",
+ "D-pad Down",
+ "D-pad Left",
+ "D-pad Right",
+ "Mute",
+ "P1",
+ "P2",
+ "P3",
+ "P4",
+ "Touchpad" };
+
+char const *const CONTROLLER_BUTTON_PS4[]{
+ "Cross",
+ "Circle",
+ "Square",
+ "Triangle",
+ "Share",
+ "PS",
+ "Options",
+ "L3",
+ "R3",
+ "L1",
+ "R1",
+ "D-pad Up",
+ "D-pad Down",
+ "D-pad Left",
+ "D-pad Right",
+ "Mute",
+ "P1",
+ "P2",
+ "P3",
+ "P4",
+ "Touchpad" };
+
+char const *const CONTROLLER_BUTTON_PS5[]{
+ "Cross",
+ "Circle",
+ "Square",
+ "Triangle",
+ "Create",
+ "PS",
+ "Options",
+ "L3",
+ "R3",
+ "L1",
+ "R1",
+ "D-pad Up",
+ "D-pad Down",
+ "D-pad Left",
+ "D-pad Right",
+ "Mute",
+ "P1",
+ "P2",
+ "P3",
+ "P4",
+ "Touchpad" };
+
+char const *const CONTROLLER_BUTTON_SWITCH[]{
+ "A",
+ "B",
+ "X",
+ "Y",
+ "-",
+ "Home",
+ "+",
+ "LSB",
+ "RSB",
+ "L",
+ "R",
+ "D-pad Up",
+ "D-pad Down",
+ "D-pad Left",
+ "D-pad Right",
+ "Capture",
+ "RSR",
+ "LSL",
+ "RSL",
+ "LSR",
+ "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" };
+
+[[maybe_unused]] char const *const CONTROLLER_BUTTON_SHIELD[]{
+ "A",
+ "B",
+ "X",
+ "Y",
+ "Back",
+ "Logo",
+ "Start",
+ "LSB",
+ "RSB",
+ "LB",
+ "RB",
+ "D-pad Up",
+ "D-pad Down",
+ "D-pad Left",
+ "D-pad Right",
+ "Share",
+ "P1",
+ "P2",
+ "P3",
+ "P4",
+ "Touchpad" };
struct key_lookup_table
{
@@ -56,12 +271,8 @@ struct key_lookup_table
};
#define KE(x) { SDL_SCANCODE_ ## x, "SDL_SCANCODE_" #x },
-#define KE8(A, B, C, D, E, F, G, H) KE(A) KE(B) KE(C) KE(D) KE(E) KE(F) KE(G) KE(H)
-#define KE7(A, B, C, D, E, F, G) KE(A) KE(B) KE(C) KE(D) KE(E) KE(F) KE(G)
-#define KE5(A, B, C, D, E) KE(A) KE(B) KE(C) KE(D) KE(E)
-#define KE3(A, B, C) KE(A) KE(B) KE(C)
-static key_lookup_table sdl_lookup_table[] =
+key_lookup_table const sdl_lookup_table[] =
{
KE(UNKNOWN)
@@ -320,520 +531,1711 @@ static key_lookup_table sdl_lookup_table[] =
KE(APP1)
KE(APP2)
+};
+
+//============================================================
+// lookup_sdl_code
+//============================================================
+int lookup_sdl_code(std::string_view scode)
{
- -1, ""
+ auto const found = std::find_if(
+ std::begin(sdl_lookup_table),
+ std::end(sdl_lookup_table),
+ [&scode] (auto const &key) { return scode == key.name; });
+ return (std::end(sdl_lookup_table) != found) ? found->code : -1;
}
-};
+
//============================================================
-// lookup_sdl_code
+// sdl_device
//============================================================
-static int lookup_sdl_code(const char *scode)
+using sdl_device = event_based_device<SDL_Event>;
+
+
+//============================================================
+// sdl_keyboard_device
+//============================================================
+
+class sdl_keyboard_device : public sdl_device
{
- int i = 0;
+public:
+ sdl_keyboard_device(
+ std::string &&name,
+ std::string &&id,
+ input_module &module,
+ keyboard_trans_table const &trans_table) :
+ sdl_device(std::move(name), std::move(id), module),
+ m_trans_table(trans_table),
+ m_keyboard({{0}}),
+ m_capslock_pressed(std::chrono::steady_clock::time_point::min())
+ {
+ }
- while (sdl_lookup_table[i].code >= 0)
+ virtual void poll(bool relative_reset) override
{
- if (!strcmp(scode, sdl_lookup_table[i].name))
- return sdl_lookup_table[i].code;
- i++;
+ sdl_device::poll(relative_reset);
+
+#ifdef __APPLE__
+ if (m_keyboard.state[SDL_SCANCODE_CAPSLOCK] && (std::chrono::steady_clock::now() > (m_capslock_pressed + std::chrono::milliseconds(30))))
+ m_keyboard.state[SDL_SCANCODE_CAPSLOCK] = 0x00;
+#endif
}
- return -1;
-}
+
+ virtual void process_event(SDL_Event const &event) override
+ {
+ switch (event.type)
+ {
+ case SDL_KEYDOWN:
+ if (event.key.keysym.scancode == SDL_SCANCODE_CAPSLOCK)
+ m_capslock_pressed = std::chrono::steady_clock::now();
+
+ m_keyboard.state[event.key.keysym.scancode] = 0x80;
+ break;
+
+ case SDL_KEYUP:
+#ifdef __APPLE__
+ if (event.key.keysym.scancode == SDL_SCANCODE_CAPSLOCK)
+ break;
+#endif
+
+ m_keyboard.state[event.key.keysym.scancode] = 0x00;
+ break;
+ }
+ }
+
+ virtual void reset() override
+ {
+ sdl_device::reset();
+ memset(&m_keyboard.state, 0, sizeof(m_keyboard.state));
+ m_capslock_pressed = std::chrono::steady_clock::time_point::min();
+ }
+
+ virtual void configure(input_device &device) override
+ {
+ // populate it
+ for (int keynum = 0; m_trans_table[keynum].mame_key != ITEM_ID_INVALID; keynum++)
+ {
+ input_item_id itemid = m_trans_table[keynum].mame_key;
+ device.add_item(
+ m_trans_table[keynum].ui_name,
+ std::string_view(),
+ itemid,
+ generic_button_get_state<s32>,
+ &m_keyboard.state[m_trans_table[keynum].sdl_scancode]);
+ }
+ }
+
+private:
+ // state information for a keyboard
+ struct keyboard_state
+ {
+ s32 state[0x3ff]; // must be s32!
+ s8 oldkey[MAX_KEYS];
+ s8 currkey[MAX_KEYS];
+ };
+
+ keyboard_trans_table const &m_trans_table;
+ keyboard_state m_keyboard;
+ std::chrono::steady_clock::time_point m_capslock_pressed;
+};
+
//============================================================
-// sdl_device
+// sdl_mouse_device_base
//============================================================
-class sdl_device : public event_based_device<SDL_Event>
+class sdl_mouse_device_base : public sdl_device
{
public:
- sdl_device(running_machine &machine, const char *name, const char *id, input_device_class devclass, input_module &module)
- : event_based_device(machine, name, id, devclass, module)
+ virtual void poll(bool relative_reset) override
{
+ sdl_device::poll(relative_reset);
+
+ if (relative_reset)
+ {
+ m_mouse.lV = std::exchange(m_v, 0);
+ m_mouse.lH = std::exchange(m_h, 0);
+ }
+ }
+
+ virtual void reset() override
+ {
+ sdl_device::reset();
+ memset(&m_mouse, 0, sizeof(m_mouse));
+ m_v = m_h = 0;
}
protected:
- std::shared_ptr<sdl_window_info> focus_window()
+ // state information for a mouse
+ struct mouse_state
+ {
+ s32 lX, lY, lV, lH;
+ s32 buttons[MAX_BUTTONS];
+ };
+
+ sdl_mouse_device_base(std::string &&name, std::string &&id, input_module &module) :
+ sdl_device(std::move(name), std::move(id), module),
+ m_mouse({0}),
+ m_v(0),
+ m_h(0)
{
- return sdl_event_manager::instance().focus_window();
}
+
+ void add_common_items(input_device &device, unsigned buttons)
+ {
+ // add horizontal and vertical axes - relative for a mouse or absolute for a gun
+ device.add_item(
+ "X",
+ std::string_view(),
+ ITEM_ID_XAXIS,
+ generic_axis_get_state<s32>,
+ &m_mouse.lX);
+ device.add_item(
+ "Y",
+ std::string_view(),
+ ITEM_ID_YAXIS,
+ generic_axis_get_state<s32>,
+ &m_mouse.lY);
+
+ // add buttons
+ for (int button = 0; button < buttons; button++)
+ {
+ input_item_id itemid = (input_item_id)(ITEM_ID_BUTTON1 + button);
+ int const offset = button ^ (((1 == button) || (2 == button)) ? 3 : 0);
+ device.add_item(
+ default_button_name(button),
+ std::string_view(),
+ itemid,
+ generic_button_get_state<s32>,
+ &m_mouse.buttons[offset]);
+ }
+ }
+
+ mouse_state m_mouse;
+ s32 m_v, m_h;
};
+
//============================================================
-// sdl_keyboard_device
+// sdl_mouse_device
//============================================================
-class sdl_keyboard_device : public sdl_device
+class sdl_mouse_device : public sdl_mouse_device_base
{
public:
- keyboard_state keyboard;
+ sdl_mouse_device(std::string &&name, std::string &&id, input_module &module) :
+ sdl_mouse_device_base(std::move(name), std::move(id), module),
+ m_x(0),
+ m_y(0)
+ {
+ }
- sdl_keyboard_device(running_machine &machine, const char *name, const char *id, input_module &module)
- : sdl_device(machine, name, id, DEVICE_CLASS_KEYBOARD, module),
- keyboard({{0}})
+ virtual void poll(bool relative_reset) override
{
+ sdl_mouse_device_base::poll(relative_reset);
+
+ if (relative_reset)
+ {
+ m_mouse.lX = std::exchange(m_x, 0);
+ m_mouse.lY = std::exchange(m_y, 0);
+ }
}
- void process_event(SDL_Event &sdlevent) override
+ virtual void reset() override
{
- switch (sdlevent.type)
+ sdl_mouse_device_base::reset();
+ m_x = m_y = 0;
+ }
+
+ virtual void configure(input_device &device) override
+ {
+ add_common_items(device, 5);
+
+ // add scroll axes
+ device.add_item(
+ "Scroll V",
+ std::string_view(),
+ ITEM_ID_ZAXIS,
+ generic_axis_get_state<s32>,
+ &m_mouse.lV);
+ device.add_item(
+ "Scroll H",
+ std::string_view(),
+ ITEM_ID_RZAXIS,
+ generic_axis_get_state<s32>,
+ &m_mouse.lH);
+ }
+
+ virtual void process_event(SDL_Event const &event) override
+ {
+ switch (event.type)
{
- case SDL_KEYDOWN:
- keyboard.state[sdlevent.key.keysym.scancode] = 0x80;
- if (sdlevent.key.keysym.sym < 0x20)
- machine().ui_input().push_char_event(osd_common_t::s_window_list.front()->target(), sdlevent.key.keysym.sym);
+ case SDL_MOUSEMOTION:
+ m_x += event.motion.xrel * input_device::RELATIVE_PER_PIXEL;
+ m_y += event.motion.yrel * input_device::RELATIVE_PER_PIXEL;
break;
- case SDL_KEYUP:
- keyboard.state[sdlevent.key.keysym.scancode] = 0x00;
+ case SDL_MOUSEBUTTONDOWN:
+ m_mouse.buttons[event.button.button - 1] = 0x80;
break;
- case SDL_TEXTINPUT:
- if (*sdlevent.text.text)
- {
- auto window = GET_FOCUS_WINDOW(&event.text);
- //printf("Focus window is %p - wl %p\n", window, osd_common_t::s_window_list);
- if (window != nullptr)
- {
- auto ptr = sdlevent.text.text;
- auto len = std::strlen(sdlevent.text.text);
- while (len)
- {
- char32_t ch;
- auto chlen = uchar_from_utf8(&ch, ptr, len);
- if (0 > chlen)
- {
- ch = 0x0fffd;
- chlen = 1;
- }
- ptr += chlen;
- len -= chlen;
- machine().ui_input().push_char_event(window->target(), ch);
- }
- }
- }
+ case SDL_MOUSEBUTTONUP:
+ m_mouse.buttons[event.button.button - 1] = 0;
+ break;
+
+ case SDL_MOUSEWHEEL:
+ // adjust SDL 1-per-click to match Win32 120-per-click
+#if SDL_VERSION_ATLEAST(2, 0, 18)
+ m_v += std::lround(event.wheel.preciseY * 120 * input_device::RELATIVE_PER_PIXEL);
+ m_h += std::lround(event.wheel.preciseX * 120 * input_device::RELATIVE_PER_PIXEL);
+#else
+ m_v += event.wheel.y * 120 * input_device::RELATIVE_PER_PIXEL;
+ m_h += event.wheel.x * 120 * input_device::RELATIVE_PER_PIXEL;
+#endif
break;
}
}
- void reset() override
- {
- memset(&keyboard.state, 0, sizeof(keyboard.state));
- }
+private:
+ s32 m_x, m_y;
};
+
//============================================================
-// sdl_mouse_device
+// sdl_lightgun_device
//============================================================
-class sdl_mouse_device : public sdl_device
+class sdl_lightgun_device : public sdl_mouse_device_base
{
-private:
- const std::chrono::milliseconds double_click_speed = std::chrono::milliseconds(250);
- std::chrono::system_clock::time_point last_click;
- int last_x;
- int last_y;
-
public:
- mouse_state mouse;
+ sdl_lightgun_device(std::string &&name, std::string &&id, input_module &module) :
+ sdl_mouse_device_base(std::move(name), std::move(id), module),
+ m_x(0),
+ m_y(0),
+ m_window(0)
+ {
+ }
- sdl_mouse_device(running_machine &machine, const char *name, const char *id, input_module &module)
- : sdl_device(machine, name, id, DEVICE_CLASS_MOUSE, module),
- last_x(0),
- last_y(0),
- mouse({0})
+ virtual void poll(bool relative_reset) override
{
+ sdl_mouse_device_base::poll(relative_reset);
+
+ SDL_Window *const win(m_window ? SDL_GetWindowFromID(m_window) : nullptr);
+ if (win)
+ {
+ int w, h;
+ SDL_GetWindowSize(win, &w, &h);
+ m_mouse.lX = normalize_absolute_axis(m_x, 0, w - 1);
+ m_mouse.lY = normalize_absolute_axis(m_y, 0, h - 1);
+ }
+ else
+ {
+ m_mouse.lX = 0;
+ m_mouse.lY = 0;
+ }
}
- void reset() override
+ virtual void reset() override
{
- memset(&mouse, 0, sizeof(mouse));
+ sdl_mouse_device_base::reset();
+ m_x = m_y = 0;
+ m_window = 0;
}
- void poll() override
+ virtual void configure(input_device &device) override
{
- mouse.lX = 0;
- mouse.lY = 0;
- sdl_device::poll();
+ add_common_items(device, 5);
+
+ // add scroll axes
+ device.add_item(
+ "Scroll V",
+ std::string_view(),
+ ITEM_ID_ADD_RELATIVE1,
+ generic_axis_get_state<s32>,
+ &m_mouse.lV);
+ device.add_item(
+ "Scroll H",
+ std::string_view(),
+ ITEM_ID_ADD_RELATIVE2,
+ generic_axis_get_state<s32>,
+ &m_mouse.lH);
}
- virtual void process_event(SDL_Event &sdlevent) override
+ virtual void process_event(SDL_Event const &event) override
{
- switch (sdlevent.type)
+ switch (event.type)
{
case SDL_MOUSEMOTION:
- mouse.lX += sdlevent.motion.xrel * INPUT_RELATIVE_PER_PIXEL;
- mouse.lY += sdlevent.motion.yrel * INPUT_RELATIVE_PER_PIXEL;
-
- {
- int cx = -1, cy = -1;
- auto window = GET_FOCUS_WINDOW(&sdlevent.motion);
-
- if (window != nullptr && window->xy_to_render_target(sdlevent.motion.x, sdlevent.motion.y, &cx, &cy))
- machine().ui_input().push_mouse_move_event(window->target(), cx, cy);
- }
+ m_x = event.motion.x;
+ m_y = event.motion.y;
+ m_window = event.motion.windowID;
break;
case SDL_MOUSEBUTTONDOWN:
- mouse.buttons[sdlevent.button.button - 1] = 0x80;
- //printf("But down %d %d %d %d %s\n", event.button.which, event.button.button, event.button.x, event.button.y, devinfo->name.c_str());
- if (sdlevent.button.button == 1)
- {
- int cx, cy;
- auto click = std::chrono::system_clock::now();
- auto window = GET_FOCUS_WINDOW(&sdlevent.button);
- if (window != nullptr && window->xy_to_render_target(sdlevent.button.x, sdlevent.button.y, &cx, &cy))
- {
- machine().ui_input().push_mouse_down_event(window->target(), cx, cy);
+ m_mouse.buttons[event.button.button - 1] = 0x80;
+ m_x = event.button.x;
+ m_y = event.button.y;
+ m_window = event.button.windowID;
+ break;
- // avoid overflow with std::chrono::time_point::min() by adding rather than subtracting
- if (click < last_click + double_click_speed
- && (cx >= last_x - 4 && cx <= last_x + 4)
- && (cy >= last_y - 4 && cy <= last_y + 4))
- {
- last_click = std::chrono::time_point<std::chrono::system_clock>::min();
- machine().ui_input().push_mouse_double_click_event(window->target(), cx, cy);
- }
- else
- {
- last_click = click;
- last_x = cx;
- last_y = cy;
- }
- }
- }
+ case SDL_MOUSEBUTTONUP:
+ m_mouse.buttons[event.button.button - 1] = 0;
+ m_x = event.button.x;
+ m_y = event.button.y;
+ m_window = event.button.windowID;
+ break;
- else if (sdlevent.button.button == 3)
- {
- int cx, cy;
- auto window = GET_FOCUS_WINDOW(&sdlevent.button);
+ case SDL_MOUSEWHEEL:
+ // adjust SDL 1-per-click to match Win32 120-per-click
+#if SDL_VERSION_ATLEAST(2, 0, 18)
+ m_v += std::lround(event.wheel.preciseY * 120 * input_device::RELATIVE_PER_PIXEL);
+ m_h += std::lround(event.wheel.preciseX * 120 * input_device::RELATIVE_PER_PIXEL);
+#else
+ m_v += event.wheel.y * 120 * input_device::RELATIVE_PER_PIXEL;
+ m_h += event.wheel.x * 120 * input_device::RELATIVE_PER_PIXEL;
+#endif
+ break;
- if (window != nullptr && window->xy_to_render_target(sdlevent.button.x, sdlevent.button.y, &cx, &cy))
- {
- machine().ui_input().push_mouse_rdown_event(window->target(), cx, cy);
- }
- }
+ case SDL_WINDOWEVENT:
+ if ((event.window.windowID == m_window) && (SDL_WINDOWEVENT_LEAVE == event.window.event))
+ m_window = 0;
break;
+ }
+ }
- case SDL_MOUSEBUTTONUP:
- mouse.buttons[sdlevent.button.button - 1] = 0;
- //printf("But up %d %d %d %d\n", event.button.which, event.button.button, event.button.x, event.button.y);
+private:
+ s32 m_x, m_y;
+ u32 m_window;
+};
- if (sdlevent.button.button == 1)
- {
- int cx, cy;
- auto window = GET_FOCUS_WINDOW(&sdlevent.button);
- if (window != nullptr && window->xy_to_render_target(sdlevent.button.x, sdlevent.button.y, &cx, &cy))
- {
- machine().ui_input().push_mouse_up_event(window->target(), cx, cy);
- }
- }
- else if (sdlevent.button.button == 3)
- {
- int cx, cy;
- auto window = GET_FOCUS_WINDOW(&sdlevent.button);
+//============================================================
+// sdl_dual_lightgun_device
+//============================================================
+
+class sdl_dual_lightgun_device : public sdl_mouse_device_base
+{
+public:
+ sdl_dual_lightgun_device(std::string &&name, std::string &&id, input_module &module, u8 index) :
+ sdl_mouse_device_base(std::move(name), std::move(id), module),
+ m_index(index)
+ {
+ }
+
+ virtual void configure(input_device &device) override
+ {
+ add_common_items(device, 2);
+ }
- if (window != nullptr && window->xy_to_render_target(sdlevent.button.x, sdlevent.button.y, &cx, &cy))
+ virtual void process_event(SDL_Event const &event) override
+ {
+ switch (event.type)
+ {
+ case SDL_MOUSEBUTTONDOWN:
+ {
+ SDL_Window *const win(SDL_GetWindowFromID(event.button.windowID));
+ u8 const button = translate_button(event);
+ if (win && ((button / 2) == m_index))
{
- machine().ui_input().push_mouse_rup_event(window->target(), cx, cy);
+ int w, h;
+ SDL_GetWindowSize(win, &w, &h);
+ m_mouse.buttons[(button & 1) << 1] = 0x80;
+ m_mouse.lX = normalize_absolute_axis(event.button.x, 0, w - 1);
+ m_mouse.lY = normalize_absolute_axis(event.button.y, 0, h - 1);
}
}
break;
- case SDL_MOUSEWHEEL:
- auto window = GET_FOCUS_WINDOW(&sdlevent.wheel);
- if (window != nullptr)
- machine().ui_input().push_mouse_wheel_event(window->target(), 0, 0, sdlevent.wheel.y, 3);
+ case SDL_MOUSEBUTTONUP:
+ {
+ u8 const button = translate_button(event);
+ if ((button / 2) == m_index)
+ m_mouse.buttons[(button & 1) << 1] = 0;
+ }
break;
}
}
+
+private:
+ static u8 translate_button(SDL_Event const &event)
+ {
+ u8 const index(event.button.button - 1);
+ return index ^ (((1 == index) || (2 == index)) ? 3 : 0);
+ }
+
+ u8 const m_index;
};
+
//============================================================
-// sdl_joystick_device
+// sdl_joystick_device_base
//============================================================
-// state information for a joystick
-struct sdl_joystick_state
+class sdl_joystick_device_base : public sdl_device, protected joystick_assignment_helper
{
- 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];
-};
+public:
+ std::optional<std::string> const &serial() const { return m_serial; }
+ SDL_JoystickID instance() const { return m_instance; }
-struct sdl_api_state
-{
- SDL_Joystick *device;
- SDL_Haptic *hapdevice;
- SDL_JoystickID joystick_id;
-};
+ bool is_instance(SDL_JoystickID instance) const { return m_instance == instance; }
-class sdl_joystick_device : public sdl_device
-{
-public:
- sdl_joystick_state joystick;
- sdl_api_state sdl_state;
+ bool reconnect_match(std::string_view g, char const *s) const
+ {
+ return
+ (0 > m_instance) &&
+ (id() == g) &&
+ ((s && serial() && (*serial() == s)) || (!s && !serial()));
+ }
- sdl_joystick_device(running_machine &machine, const char *name, const char *id, input_module &module)
- : sdl_device(machine, name, id, DEVICE_CLASS_JOYSTICK, module),
- joystick({{0}}),
- sdl_state({ nullptr })
+protected:
+ sdl_joystick_device_base(
+ std::string &&name,
+ std::string &&id,
+ input_module &module,
+ char const *serial) :
+ sdl_device(std::move(name), std::move(id), module),
+ m_instance(-1)
{
+ if (serial)
+ m_serial = serial;
}
- ~sdl_joystick_device()
+ void set_instance(SDL_JoystickID instance)
{
- if (sdl_state.device != nullptr)
- {
- if (sdl_state.hapdevice != nullptr)
- {
- SDL_HapticClose(sdl_state.hapdevice);
- sdl_state.hapdevice = nullptr;
- }
- SDL_JoystickClose(sdl_state.device);
- sdl_state.device = nullptr;
- }
+ assert(0 > m_instance);
+ assert(0 <= instance);
+
+ m_instance = instance;
}
- void reset() override
+ void clear_instance()
+ {
+ m_instance = -1;
+ }
+
+private:
+ std::optional<std::string> m_serial;
+ SDL_JoystickID m_instance;
+};
+
+
+//============================================================
+// sdl_joystick_device
+//============================================================
+
+class sdl_joystick_device : public sdl_joystick_device_base
+{
+public:
+ sdl_joystick_device(
+ std::string &&name,
+ std::string &&id,
+ input_module &module,
+ SDL_Joystick *joy,
+ char const *serial) :
+ sdl_joystick_device_base(
+ std::move(name),
+ std::move(id),
+ module,
+ serial),
+ m_joystick({{0}}),
+ m_joydevice(joy),
+ m_hapdevice(SDL_HapticOpenFromJoystick(joy))
{
- memset(&joystick, 0, sizeof(joystick));
+ set_instance(SDL_JoystickInstanceID(joy));
}
- void process_event(SDL_Event &sdlevent) override
+ virtual void configure(input_device &device) override
{
- switch (sdlevent.type)
+ input_device::assignment_vector assignments;
+ char tempname[32];
+
+ int const axiscount = SDL_JoystickNumAxes(m_joydevice);
+ int const buttoncount = SDL_JoystickNumButtons(m_joydevice);
+ int const hatcount = SDL_JoystickNumHats(m_joydevice);
+ int const ballcount = SDL_JoystickNumBalls(m_joydevice);
+
+ // loop over all axes
+ input_item_id axisactual[MAX_AXES];
+ for (int axis = 0; (axis < MAX_AXES) && (axis < axiscount); axis++)
{
- case SDL_JOYAXISMOTION:
- joystick.axes[sdlevent.jaxis.axis] = (sdlevent.jaxis.value * 2);
- break;
+ input_item_id itemid;
- case SDL_JOYBALLMOTION:
- //printf("Ball %d %d\n", sdlevent.jball.xrel, sdlevent.jball.yrel);
- joystick.balls[sdlevent.jball.ball * 2] = sdlevent.jball.xrel * INPUT_RELATIVE_PER_PIXEL;
- joystick.balls[sdlevent.jball.ball * 2 + 1] = sdlevent.jball.yrel * INPUT_RELATIVE_PER_PIXEL;
- break;
+ if (axis < INPUT_MAX_AXIS)
+ itemid = input_item_id(ITEM_ID_XAXIS + axis);
+ else if (axis < (INPUT_MAX_AXIS + INPUT_MAX_ADD_ABSOLUTE))
+ itemid = input_item_id(ITEM_ID_ADD_ABSOLUTE1 + axis - INPUT_MAX_AXIS);
+ else
+ itemid = ITEM_ID_OTHER_AXIS_ABSOLUTE;
+
+ snprintf(tempname, sizeof(tempname), "A%d", axis + 1);
+ axisactual[axis] = device.add_item(
+ tempname,
+ std::string_view(),
+ itemid,
+ generic_axis_get_state<s32>,
+ &m_joystick.axes[axis]);
+ }
- case SDL_JOYHATMOTION:
- if (sdlevent.jhat.value & SDL_HAT_UP)
- {
- joystick.hatsU[sdlevent.jhat.hat] = 0x80;
- }
+ // loop over all buttons
+ for (int button = 0; (button < MAX_BUTTONS) && (button < buttoncount); button++)
+ {
+ input_item_id itemid;
+
+ m_joystick.buttons[button] = 0;
+
+ if (button < INPUT_MAX_BUTTONS)
+ itemid = input_item_id(ITEM_ID_BUTTON1 + button);
+ else if (button < INPUT_MAX_BUTTONS + INPUT_MAX_ADD_SWITCH)
+ itemid = input_item_id(ITEM_ID_ADD_SWITCH1 + button - INPUT_MAX_BUTTONS);
else
+ itemid = ITEM_ID_OTHER_SWITCH;
+
+ input_item_id const actual = device.add_item(
+ default_button_name(button),
+ std::string_view(),
+ itemid,
+ generic_button_get_state<s32>,
+ &m_joystick.buttons[button]);
+
+ // there are sixteen action button types
+ if (button < 16)
{
- joystick.hatsU[sdlevent.jhat.hat] = 0;
- }
- if (sdlevent.jhat.value & SDL_HAT_DOWN)
- {
- joystick.hatsD[sdlevent.jhat.hat] = 0x80;
+ input_seq const seq(make_code(ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, actual));
+ assignments.emplace_back(ioport_type(IPT_BUTTON1 + button), SEQ_TYPE_STANDARD, seq);
+
+ // assign the first few buttons to UI actions and pedals
+ switch (button)
+ {
+ case 0:
+ assignments.emplace_back(IPT_PEDAL, SEQ_TYPE_INCREMENT, seq);
+ assignments.emplace_back(IPT_UI_SELECT, SEQ_TYPE_STANDARD, seq);
+ break;
+ case 1:
+ assignments.emplace_back(IPT_PEDAL2, SEQ_TYPE_INCREMENT, seq);
+ assignments.emplace_back((3 > buttoncount) ? IPT_UI_CLEAR : IPT_UI_BACK, SEQ_TYPE_STANDARD, seq);
+ break;
+ case 2:
+ assignments.emplace_back(IPT_PEDAL3, SEQ_TYPE_INCREMENT, seq);
+ assignments.emplace_back(IPT_UI_CLEAR, SEQ_TYPE_STANDARD, seq);
+ break;
+ case 3:
+ assignments.emplace_back(IPT_UI_HELP, SEQ_TYPE_STANDARD, seq);
+ break;
+ }
}
+ }
+
+ // loop over all hats
+ input_item_id hatactual[MAX_HATS][4];
+ for (int hat = 0; (hat < MAX_HATS) && (hat < hatcount); hat++)
+ {
+ input_item_id itemid;
+
+ 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);
+ hatactual[hat][0] = device.add_item(
+ tempname,
+ std::string_view(),
+ itemid,
+ generic_button_get_state<s32>,
+ &m_joystick.hatsU[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);
+ hatactual[hat][1] = device.add_item(
+ tempname,
+ std::string_view(),
+ itemid,
+ generic_button_get_state<s32>,
+ &m_joystick.hatsD[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);
+ hatactual[hat][2] = device.add_item(
+ tempname,
+ std::string_view(),
+ itemid,
+ generic_button_get_state<s32>,
+ &m_joystick.hatsL[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);
+ hatactual[hat][3] = device.add_item(
+ tempname,
+ std::string_view(),
+ itemid,
+ generic_button_get_state<s32>,
+ &m_joystick.hatsR[hat]);
+ }
+
+ // loop over all (track)balls
+ for (int ball = 0; (ball < (MAX_AXES / 2)) && (ball < ballcount); ball++)
+ {
+ int itemid;
+
+ if (ball * 2 < INPUT_MAX_ADD_RELATIVE)
+ itemid = ITEM_ID_ADD_RELATIVE1 + ball * 2;
else
+ itemid = ITEM_ID_OTHER_AXIS_RELATIVE;
+
+ snprintf(tempname, sizeof(tempname), "R%d X", ball + 1);
+ input_item_id const xactual = device.add_item(
+ tempname,
+ std::string_view(),
+ input_item_id(itemid),
+ generic_axis_get_state<s32>,
+ &m_joystick.balls[ball * 2]);
+
+ snprintf(tempname, sizeof(tempname), "R%d Y", ball + 1);
+ input_item_id const yactual = device.add_item(
+ tempname,
+ std::string_view(),
+ input_item_id(itemid + 1),
+ generic_axis_get_state<s32>,
+ &m_joystick.balls[ball * 2 + 1]);
+
+ if (0 == ball)
{
- joystick.hatsD[sdlevent.jhat.hat] = 0;
+ // assign the first trackball to dial, trackball, mouse and lightgun inputs
+ input_seq const xseq(make_code(ITEM_CLASS_RELATIVE, ITEM_MODIFIER_NONE, xactual));
+ input_seq const yseq(make_code(ITEM_CLASS_RELATIVE, ITEM_MODIFIER_NONE, yactual));
+ assignments.emplace_back(IPT_DIAL, SEQ_TYPE_STANDARD, xseq);
+ assignments.emplace_back(IPT_DIAL_V, SEQ_TYPE_STANDARD, yseq);
+ assignments.emplace_back(IPT_TRACKBALL_X, SEQ_TYPE_STANDARD, xseq);
+ assignments.emplace_back(IPT_TRACKBALL_Y, SEQ_TYPE_STANDARD, yseq);
+ assignments.emplace_back(IPT_LIGHTGUN_X, SEQ_TYPE_STANDARD, xseq);
+ assignments.emplace_back(IPT_LIGHTGUN_Y, SEQ_TYPE_STANDARD, yseq);
+ assignments.emplace_back(IPT_MOUSE_X, SEQ_TYPE_STANDARD, xseq);
+ assignments.emplace_back(IPT_MOUSE_Y, SEQ_TYPE_STANDARD, yseq);
+ if (2 > axiscount)
+ {
+ // use it for joystick inputs if axes are limited
+ assignments.emplace_back(IPT_AD_STICK_X, SEQ_TYPE_STANDARD, xseq);
+ assignments.emplace_back(IPT_AD_STICK_Y, SEQ_TYPE_STANDARD, yseq);
+ }
+ else
+ {
+ // use for non-centring throttle control
+ assignments.emplace_back(IPT_AD_STICK_Z, SEQ_TYPE_STANDARD, yseq);
+ }
}
- if (sdlevent.jhat.value & SDL_HAT_LEFT)
+ else if ((1 == ball) && (2 > axiscount))
{
- joystick.hatsL[sdlevent.jhat.hat] = 0x80;
+ // provide a non-centring throttle control
+ input_seq const yseq(make_code(ITEM_CLASS_RELATIVE, ITEM_MODIFIER_NONE, yactual));
+ assignments.emplace_back(IPT_AD_STICK_Z, SEQ_TYPE_STANDARD, yseq);
}
- else
+ }
+
+ // set up default assignments for axes and hats
+ add_directional_assignments(
+ assignments,
+ (1 <= axiscount) ? axisactual[0] : ITEM_ID_INVALID, // assume first axis is X
+ (2 <= axiscount) ? axisactual[1] : ITEM_ID_INVALID, // assume second axis is Y
+ (1 <= hatcount) ? hatactual[0][2] : ITEM_ID_INVALID,
+ (1 <= hatcount) ? hatactual[0][3] : ITEM_ID_INVALID,
+ (1 <= hatcount) ? hatactual[0][0] : ITEM_ID_INVALID,
+ (1 <= hatcount) ? hatactual[0][1] : ITEM_ID_INVALID);
+ if (2 <= axiscount)
+ {
+ // put pedals on the last of the second, third or fourth axis
+ input_item_id const pedalitem = axisactual[(std::min)(axiscount, 4) - 1];
+ assignments.emplace_back(
+ IPT_PEDAL,
+ SEQ_TYPE_STANDARD,
+ input_seq(make_code(ITEM_CLASS_ABSOLUTE, ITEM_MODIFIER_NEG, pedalitem)));
+ assignments.emplace_back(
+ IPT_PEDAL2,
+ SEQ_TYPE_STANDARD,
+ input_seq(make_code(ITEM_CLASS_ABSOLUTE, ITEM_MODIFIER_POS, pedalitem)));
+ }
+ if (3 <= axiscount)
+ {
+ // assign X/Y to one of the twin sticks
+ assignments.emplace_back(
+ (4 <= axiscount) ? IPT_JOYSTICKLEFT_LEFT : IPT_JOYSTICKRIGHT_LEFT,
+ SEQ_TYPE_STANDARD,
+ input_seq(make_code(ITEM_CLASS_SWITCH, ITEM_MODIFIER_LEFT, axisactual[0])));
+ assignments.emplace_back(
+ (4 <= axiscount) ? IPT_JOYSTICKLEFT_RIGHT : IPT_JOYSTICKRIGHT_RIGHT,
+ SEQ_TYPE_STANDARD,
+ input_seq(make_code(ITEM_CLASS_SWITCH, ITEM_MODIFIER_RIGHT, axisactual[0])));
+ assignments.emplace_back(
+ (4 <= axiscount) ? IPT_JOYSTICKLEFT_UP : IPT_JOYSTICKRIGHT_UP,
+ SEQ_TYPE_STANDARD,
+ input_seq(make_code(ITEM_CLASS_SWITCH, ITEM_MODIFIER_UP, axisactual[1])));
+ assignments.emplace_back(
+ (4 <= axiscount) ? IPT_JOYSTICKLEFT_DOWN : IPT_JOYSTICKRIGHT_DOWN,
+ SEQ_TYPE_STANDARD,
+ input_seq(make_code(ITEM_CLASS_SWITCH, ITEM_MODIFIER_DOWN, axisactual[1])));
+
+ // use third or fourth axis for Z
+ input_seq const seq(make_code(ITEM_CLASS_ABSOLUTE, ITEM_MODIFIER_NONE, axisactual[(std::min)(axiscount, 4) - 1]));
+ assignments.emplace_back(IPT_AD_STICK_Z, SEQ_TYPE_STANDARD, seq);
+
+ // use this for focus next/previous to make system selection menu practical to navigate
+ input_seq const upseq(make_code(ITEM_CLASS_SWITCH, ITEM_MODIFIER_NEG, axisactual[2]));
+ input_seq const downseq(make_code(ITEM_CLASS_SWITCH, ITEM_MODIFIER_POS, axisactual[2]));
+ assignments.emplace_back(IPT_UI_FOCUS_PREV, SEQ_TYPE_STANDARD, upseq);
+ assignments.emplace_back(IPT_UI_FOCUS_NEXT, SEQ_TYPE_STANDARD, downseq);
+ if (4 <= axiscount)
{
- joystick.hatsL[sdlevent.jhat.hat] = 0;
+ // use for zoom as well if there's another axis to use for previous/next group
+ assignments.emplace_back(IPT_UI_ZOOM_IN, SEQ_TYPE_STANDARD, downseq);
+ assignments.emplace_back(IPT_UI_ZOOM_OUT, SEQ_TYPE_STANDARD, upseq);
}
- if (sdlevent.jhat.value & SDL_HAT_RIGHT)
+
+ // use this for twin sticks, too
+ assignments.emplace_back((4 <= axiscount) ? IPT_JOYSTICKRIGHT_LEFT : IPT_JOYSTICKLEFT_UP, SEQ_TYPE_STANDARD, upseq);
+ assignments.emplace_back((4 <= axiscount) ? IPT_JOYSTICKRIGHT_RIGHT : IPT_JOYSTICKLEFT_DOWN, SEQ_TYPE_STANDARD, downseq);
+
+ // put previous/next group on the last of the third or fourth axis
+ input_item_id const groupitem = axisactual[(std::min)(axiscount, 4) - 1];
+ assignments.emplace_back(
+ IPT_UI_PREV_GROUP,
+ SEQ_TYPE_STANDARD,
+ input_seq(make_code(ITEM_CLASS_SWITCH, ITEM_MODIFIER_NEG, groupitem)));
+ assignments.emplace_back(
+ IPT_UI_NEXT_GROUP,
+ SEQ_TYPE_STANDARD,
+ input_seq(make_code(ITEM_CLASS_SWITCH, ITEM_MODIFIER_POS, groupitem)));
+ }
+ if (4 <= axiscount)
+ {
+ // use this for twin sticks
+ input_seq const upseq(make_code(ITEM_CLASS_SWITCH, ITEM_MODIFIER_NEG, axisactual[3]));
+ input_seq const downseq(make_code(ITEM_CLASS_SWITCH, ITEM_MODIFIER_POS, axisactual[3]));
+ assignments.emplace_back(IPT_JOYSTICKRIGHT_UP, SEQ_TYPE_STANDARD, upseq);
+ assignments.emplace_back(IPT_JOYSTICKRIGHT_DOWN, SEQ_TYPE_STANDARD, downseq);
+ }
+
+ // set default assignments
+ device.set_default_assignments(std::move(assignments));
+ }
+
+ ~sdl_joystick_device()
+ {
+ close_device();
+ }
+
+ virtual void reset() override
+ {
+ sdl_joystick_device_base::reset();
+ clear_buffer();
+ }
+
+ virtual void process_event(SDL_Event const &event) override
+ {
+ if (!m_joydevice)
+ return;
+
+ switch (event.type)
+ {
+ case SDL_JOYAXISMOTION:
+ if (event.jaxis.axis < MAX_AXES)
+ m_joystick.axes[event.jaxis.axis] = (event.jaxis.value * 2);
+ break;
+
+ case SDL_JOYBALLMOTION:
+ //printf("Ball %d %d\n", event.jball.xrel, event.jball.yrel);
+ if (event.jball.ball < (MAX_AXES / 2))
{
- joystick.hatsR[sdlevent.jhat.hat] = 0x80;
+ m_joystick.balls[event.jball.ball * 2] = event.jball.xrel * input_device::RELATIVE_PER_PIXEL;
+ m_joystick.balls[event.jball.ball * 2 + 1] = event.jball.yrel * input_device::RELATIVE_PER_PIXEL;
}
- else
+ break;
+
+ case SDL_JOYHATMOTION:
+ if (event.jhat.hat < MAX_HATS)
{
- joystick.hatsR[sdlevent.jhat.hat] = 0;
+ m_joystick.hatsU[event.jhat.hat] = (event.jhat.value & SDL_HAT_UP) ? 0x80 : 0;
+ m_joystick.hatsD[event.jhat.hat] = (event.jhat.value & SDL_HAT_DOWN) ? 0x80 : 0;
+ m_joystick.hatsL[event.jhat.hat] = (event.jhat.value & SDL_HAT_LEFT) ? 0x80 : 0;
+ m_joystick.hatsR[event.jhat.hat] = (event.jhat.value & SDL_HAT_RIGHT) ? 0x80 : 0;
}
break;
case SDL_JOYBUTTONDOWN:
case SDL_JOYBUTTONUP:
- joystick.buttons[sdlevent.jbutton.button] = (sdlevent.jbutton.state == SDL_PRESSED) ? 0x80 : 0;
+ if (event.jbutton.button < MAX_BUTTONS)
+ m_joystick.buttons[event.jbutton.button] = (event.jbutton.state == SDL_PRESSED) ? 0x80 : 0;
break;
+
+ case SDL_JOYDEVICEREMOVED:
+ osd_printf_verbose("Joystick: %s [ID %s] disconnected\n", name(), id());
+ clear_instance();
+ clear_buffer();
+ close_device();
+ break;
+ }
+ }
+
+ bool has_haptic() const
+ {
+ return m_hapdevice != nullptr;
+ }
+
+ void attach_device(SDL_Joystick *joy)
+ {
+ assert(joy);
+ assert(!m_joydevice);
+
+ 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:
+ // state information for a joystick
+ struct sdl_joystick_state
+ {
+ s32 axes[MAX_AXES];
+ s32 buttons[MAX_BUTTONS];
+ s32 hatsU[MAX_HATS], hatsD[MAX_HATS], hatsL[MAX_HATS], hatsR[MAX_HATS];
+ s32 balls[MAX_AXES];
+ };
+
+ sdl_joystick_state m_joystick;
+
+private:
+ SDL_Joystick *m_joydevice;
+ SDL_Haptic *m_hapdevice;
+
+ void clear_buffer()
+ {
+ memset(&m_joystick, 0, sizeof(m_joystick));
+ }
+
+ void close_device()
+ {
+ if (m_joydevice)
+ {
+ if (m_hapdevice)
+ {
+ SDL_HapticClose(m_hapdevice);
+ m_hapdevice = nullptr;
+ }
+ SDL_JoystickClose(m_joydevice);
+ m_joydevice = nullptr;
}
}
};
+
+//============================================================
+// sdl_sixaxis_joystick_device
+//============================================================
+
class sdl_sixaxis_joystick_device : public sdl_joystick_device
{
public:
- sdl_sixaxis_joystick_device(running_machine &machine, const char *name, const char *id, input_module &module)
- : sdl_joystick_device(machine, name, id, module)
- {
- }
+ using sdl_joystick_device::sdl_joystick_device;
- void process_event(SDL_Event &sdlevent) override
+ virtual void process_event(SDL_Event const &event) override
{
- switch (sdlevent.type)
+ switch (event.type)
{
case SDL_JOYAXISMOTION:
{
- int axis = sdlevent.jaxis.axis;
-
+ int const axis = event.jaxis.axis;
if (axis <= 3)
{
- joystick.axes[sdlevent.jaxis.axis] = (sdlevent.jaxis.value * 2);
+ m_joystick.axes[event.jaxis.axis] = (event.jaxis.value * 2);
}
else
{
- int magic = (sdlevent.jaxis.value / 2) + 16384;
- joystick.axes[sdlevent.jaxis.axis] = magic;
+ int const magic = (event.jaxis.value / 2) + 16384;
+ m_joystick.axes[event.jaxis.axis] = magic;
}
}
break;
default:
// Call the base for other events
- sdl_joystick_device::process_event(sdlevent);
+ sdl_joystick_device::process_event(event);
break;
}
}
};
+
//============================================================
-// sdl_input_module
+// sdl_game_controller_device
//============================================================
-class sdl_input_module : public input_module_base, public sdl_event_subscriber
+class sdl_game_controller_device : public sdl_joystick_device_base
{
public:
- sdl_input_module(const char *type)
- : input_module_base(type, "sdl")
+ sdl_game_controller_device(
+ std::string &&name,
+ std::string &&id,
+ input_module &module,
+ SDL_GameController *ctrl,
+ char const *serial) :
+ sdl_joystick_device_base(
+ std::move(name),
+ std::move(id),
+ module,
+ serial),
+ m_controller({{0}}),
+ m_ctrldevice(ctrl)
+ {
+ set_instance(SDL_JoystickInstanceID(SDL_GameControllerGetJoystick(ctrl)));
+ }
+
+ ~sdl_game_controller_device()
{
+ close_device();
}
- void input_init(running_machine &machine) override
+ virtual void configure(input_device &device) override
{
- if (machine.debug_flags & DEBUG_FLAG_OSD_ENABLED)
+ input_device::assignment_vector assignments;
+ char const *const *axisnames = CONTROLLER_AXIS_XBOX;
+ char const *const *buttonnames = CONTROLLER_BUTTON_XBOX360;
+ bool digitaltriggers = false;
+ bool avoidpaddles = false;
+ auto const ctrltype = SDL_GameControllerGetType(m_ctrldevice);
+ switch (ctrltype)
+ {
+ case SDL_CONTROLLER_TYPE_UNKNOWN:
+ osd_printf_verbose("Game Controller: ... unknown type\n", int(ctrltype));
+ break;
+ case SDL_CONTROLLER_TYPE_XBOX360:
+ osd_printf_verbose("Game Controller: ... Xbox 360 type\n");
+ axisnames = CONTROLLER_AXIS_XBOX;
+ buttonnames = CONTROLLER_BUTTON_XBOX360;
+ break;
+ case SDL_CONTROLLER_TYPE_XBOXONE:
+ osd_printf_verbose("Game Controller: ... Xbox One type\n");
+ axisnames = CONTROLLER_AXIS_XBOX;
+ buttonnames = CONTROLLER_BUTTON_XBOXONE;
+ break;
+ case SDL_CONTROLLER_TYPE_PS3:
+ osd_printf_verbose("Game Controller: ... PlayStation 3 type\n");
+ axisnames = CONTROLLER_AXIS_PS;
+ buttonnames = CONTROLLER_BUTTON_PS3;
+ break;
+ case SDL_CONTROLLER_TYPE_PS4:
+ osd_printf_verbose("Game Controller: ... PlayStation 4 type\n");
+ axisnames = CONTROLLER_AXIS_PS;
+ buttonnames = CONTROLLER_BUTTON_PS4;
+ break;
+ case SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_PRO:
+ osd_printf_verbose("Game Controller: ... Switch Pro Controller type\n");
+ axisnames = CONTROLLER_AXIS_SWITCH;
+ buttonnames = CONTROLLER_BUTTON_SWITCH;
+ digitaltriggers = true;
+ break;
+ //case SDL_CONTROLLER_TYPE_VIRTUAL:
+ case SDL_CONTROLLER_TYPE_PS5:
+ osd_printf_verbose("Game Controller: ... PlayStation 5 type\n");
+ axisnames = CONTROLLER_AXIS_PS;
+ buttonnames = CONTROLLER_BUTTON_PS5;
+ break;
+#if SDL_VERSION_ATLEAST(2, 0, 16)
+ //case SDL_CONTROLLER_TYPE_AMAZON_LUNA:
+ case SDL_CONTROLLER_TYPE_GOOGLE_STADIA:
+ osd_printf_verbose("Game Controller: ... Google Stadia type\n");
+ axisnames = CONTROLLER_AXIS_PS;
+ buttonnames = CONTROLLER_BUTTON_STADIA;
+ break;
+#endif
+#if SDL_VERSION_ATLEAST(2, 24, 0)
+ case SDL_CONTROLLER_TYPE_NVIDIA_SHIELD:
+ osd_printf_verbose("Game Controller: ... NVIDIA Shield type\n");
+ axisnames = CONTROLLER_AXIS_XBOX;
+ buttonnames = CONTROLLER_BUTTON_SHIELD;
+ break;
+ //case SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_JOYCON_LEFT:
+ //case SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_JOYCON_RIGHT:
+ case SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_JOYCON_PAIR:
+ osd_printf_verbose("Game Controller: ... Joy-Con pair type\n");
+ axisnames = CONTROLLER_AXIS_SWITCH;
+ buttonnames = CONTROLLER_BUTTON_SWITCH;
+ digitaltriggers = true;
+ avoidpaddles = true;
+ break;
+#endif
+ default: // default to Xbox 360 names
+ osd_printf_verbose("Game Controller: ... unrecognized type (%d)\n", int(ctrltype));
+ break;
+ }
+
+ // keep track of item numbers as we add controls
+ std::pair<input_item_id, input_item_id> axisitems[SDL_CONTROLLER_AXIS_MAX];
+ input_item_id buttonitems[SDL_CONTROLLER_BUTTON_MAX];
+ std::tuple<input_item_id, SDL_GameControllerButton, SDL_GameControllerAxis> numberedbuttons[16];
+ std::fill(
+ std::begin(axisitems),
+ std::end(axisitems),
+ std::make_pair(ITEM_ID_INVALID, ITEM_ID_INVALID));
+ std::fill(
+ std::begin(buttonitems),
+ std::end(buttonitems),
+ ITEM_ID_INVALID);
+ std::fill(
+ std::begin(numberedbuttons),
+ std::end(numberedbuttons),
+ std::make_tuple(ITEM_ID_INVALID, SDL_CONTROLLER_BUTTON_INVALID, SDL_CONTROLLER_AXIS_INVALID));
+
+ // add axes
+ std::tuple<SDL_GameControllerAxis, input_item_id, bool> const axes[]{
+ { SDL_CONTROLLER_AXIS_LEFTX, ITEM_ID_XAXIS, false },
+ { SDL_CONTROLLER_AXIS_LEFTY, ITEM_ID_YAXIS, false },
+ { SDL_CONTROLLER_AXIS_RIGHTX, ITEM_ID_ZAXIS, false },
+ { SDL_CONTROLLER_AXIS_RIGHTY, ITEM_ID_RZAXIS, false },
+ { SDL_CONTROLLER_AXIS_TRIGGERLEFT, ITEM_ID_SLIDER1, true },
+ { SDL_CONTROLLER_AXIS_TRIGGERRIGHT, ITEM_ID_SLIDER2, true } };
+ for (auto [axis, item, buttontest] : axes)
+ {
+ bool avail = !buttontest || !digitaltriggers;
+ avail = avail && SDL_GameControllerHasAxis(m_ctrldevice, axis);
+ if (avail)
+ {
+ auto const binding = SDL_GameControllerGetBindForAxis(m_ctrldevice, axis);
+ switch (binding.bindType)
+ {
+ case SDL_CONTROLLER_BINDTYPE_NONE:
+ avail = false;
+ break;
+ case SDL_CONTROLLER_BINDTYPE_BUTTON:
+ if (buttontest)
+ avail = false;
+ break;
+ default:
+ break;
+ }
+ }
+ if (avail)
+ {
+ axisitems[axis].first = device.add_item(
+ axisnames[axis],
+ std::string_view(),
+ item,
+ generic_axis_get_state<s32>,
+ &m_controller.axes[axis]);
+ }
+ }
+
+ // add automatically numbered buttons
+ std::tuple<SDL_GameControllerButton, SDL_GameControllerAxis, bool> const generalbuttons[]{
+ { SDL_CONTROLLER_BUTTON_A, SDL_CONTROLLER_AXIS_INVALID, true },
+ { SDL_CONTROLLER_BUTTON_B, SDL_CONTROLLER_AXIS_INVALID, true },
+ { SDL_CONTROLLER_BUTTON_X, SDL_CONTROLLER_AXIS_INVALID, true },
+ { SDL_CONTROLLER_BUTTON_Y, SDL_CONTROLLER_AXIS_INVALID, true },
+ { SDL_CONTROLLER_BUTTON_LEFTSHOULDER, SDL_CONTROLLER_AXIS_INVALID, true },
+ { SDL_CONTROLLER_BUTTON_RIGHTSHOULDER, SDL_CONTROLLER_AXIS_INVALID, true },
+ { SDL_CONTROLLER_BUTTON_INVALID, SDL_CONTROLLER_AXIS_TRIGGERLEFT, true },
+ { SDL_CONTROLLER_BUTTON_INVALID, SDL_CONTROLLER_AXIS_TRIGGERRIGHT, true },
+ { SDL_CONTROLLER_BUTTON_LEFTSTICK, SDL_CONTROLLER_AXIS_INVALID, true },
+ { SDL_CONTROLLER_BUTTON_RIGHTSTICK, SDL_CONTROLLER_AXIS_INVALID, true },
+ { SDL_CONTROLLER_BUTTON_PADDLE1, SDL_CONTROLLER_AXIS_INVALID, true },
+ { SDL_CONTROLLER_BUTTON_PADDLE2, SDL_CONTROLLER_AXIS_INVALID, true },
+ { SDL_CONTROLLER_BUTTON_PADDLE3, SDL_CONTROLLER_AXIS_INVALID, true },
+ { SDL_CONTROLLER_BUTTON_PADDLE4, SDL_CONTROLLER_AXIS_INVALID, true },
+ { SDL_CONTROLLER_BUTTON_GUIDE, SDL_CONTROLLER_AXIS_INVALID, false },
+ { SDL_CONTROLLER_BUTTON_MISC1, SDL_CONTROLLER_AXIS_INVALID, false },
+ { SDL_CONTROLLER_BUTTON_TOUCHPAD, SDL_CONTROLLER_AXIS_INVALID, false },
+ };
+ input_item_id button_item = ITEM_ID_BUTTON1;
+ unsigned buttoncount = 0;
+ for (auto [button, axis, field] : generalbuttons)
+ {
+ bool avail = true;
+ input_item_id actual = ITEM_ID_INVALID;
+ if (SDL_CONTROLLER_BUTTON_INVALID != button)
+ {
+ avail = SDL_GameControllerHasButton(m_ctrldevice, button);
+ if (avail)
+ {
+ auto const binding = SDL_GameControllerGetBindForButton(m_ctrldevice, button);
+ switch (binding.bindType)
+ {
+ case SDL_CONTROLLER_BINDTYPE_NONE:
+ avail = false;
+ break;
+ default:
+ break;
+ }
+ }
+ if (avail)
+ {
+ actual = buttonitems[button] = device.add_item(
+ buttonnames[button],
+ std::string_view(),
+ button_item++,
+ generic_button_get_state<s32>,
+ &m_controller.buttons[button]);
+ if (field && (std::size(numberedbuttons) > buttoncount))
+ std::get<1>(numberedbuttons[buttoncount]) = button;
+ }
+ }
+ else
+ {
+ avail = SDL_GameControllerHasAxis(m_ctrldevice, axis);
+ if (avail)
+ {
+ 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 = digitaltriggers;
+ }
+ }
+ if (avail)
+ {
+ actual = axisitems[axis].second = device.add_item(
+ axisnames[axis],
+ std::string_view(),
+ button_item++,
+ [] (void *device_internal, void *item_internal) -> int
+ {
+ return (*reinterpret_cast<s32 const *>(item_internal) <= -16'384) ? 1 : 0;
+ },
+ &m_controller.axes[axis]);
+ if (field && (std::size(numberedbuttons) > buttoncount))
+ std::get<2>(numberedbuttons[buttoncount]) = axis;
+ }
+ }
+
+ // add default button assignments
+ if (field && avail && (std::size(numberedbuttons) > buttoncount))
+ {
+ std::get<0>(numberedbuttons[buttoncount]) = actual;
+ add_button_assignment(assignments, ioport_type(IPT_BUTTON1 + buttoncount++), { actual });
+ }
+ }
+
+ // add buttons with fixed item IDs
+ std::pair<SDL_GameControllerButton, input_item_id> const fixedbuttons[]{
+ { SDL_CONTROLLER_BUTTON_BACK, ITEM_ID_SELECT },
+ { SDL_CONTROLLER_BUTTON_START, ITEM_ID_START },
+ { SDL_CONTROLLER_BUTTON_DPAD_UP, ITEM_ID_HAT1UP },
+ { SDL_CONTROLLER_BUTTON_DPAD_DOWN, ITEM_ID_HAT1DOWN },
+ { SDL_CONTROLLER_BUTTON_DPAD_LEFT, ITEM_ID_HAT1LEFT },
+ { SDL_CONTROLLER_BUTTON_DPAD_RIGHT, ITEM_ID_HAT1RIGHT } };
+ for (auto [button, item] : fixedbuttons)
{
- osd_printf_warning("Debug Build: Disabling input grab for -debug\n");
- set_mouse_enabled(false);
+ bool avail = true;
+ avail = SDL_GameControllerHasButton(m_ctrldevice, button);
+ if (avail)
+ {
+ auto const binding = SDL_GameControllerGetBindForButton(m_ctrldevice, button);
+ switch (binding.bindType)
+ {
+ case SDL_CONTROLLER_BINDTYPE_NONE:
+ avail = false;
+ break;
+ default:
+ break;
+ }
+ }
+ if (avail)
+ {
+ buttonitems[button] = device.add_item(
+ buttonnames[button],
+ std::string_view(),
+ item,
+ generic_button_get_state<s32>,
+ &m_controller.buttons[button]);
+ }
}
+
+ // try to get a "complete" joystick for primary movement controls
+ input_item_id diraxis[2][2];
+ choose_primary_stick(
+ diraxis,
+ axisitems[SDL_CONTROLLER_AXIS_LEFTX].first,
+ axisitems[SDL_CONTROLLER_AXIS_LEFTY].first,
+ axisitems[SDL_CONTROLLER_AXIS_RIGHTX].first,
+ axisitems[SDL_CONTROLLER_AXIS_RIGHTY].first);
+
+ // now set up controls using the primary joystick
+ add_directional_assignments(
+ assignments,
+ diraxis[0][0],
+ diraxis[0][1],
+ buttonitems[SDL_CONTROLLER_BUTTON_DPAD_LEFT],
+ buttonitems[SDL_CONTROLLER_BUTTON_DPAD_RIGHT],
+ buttonitems[SDL_CONTROLLER_BUTTON_DPAD_UP],
+ buttonitems[SDL_CONTROLLER_BUTTON_DPAD_DOWN]);
+
+ // assign a secondary stick axis to joystick Z if available
+ bool const zaxis = add_assignment(
+ assignments,
+ IPT_AD_STICK_Z,
+ SEQ_TYPE_STANDARD,
+ ITEM_CLASS_ABSOLUTE,
+ ITEM_MODIFIER_NONE,
+ { diraxis[1][1], diraxis[1][0] });
+ if (!zaxis)
+ {
+ // if both triggers are present, combine them, or failing that, fall back to a pair of buttons
+ if ((ITEM_ID_INVALID != axisitems[SDL_CONTROLLER_AXIS_TRIGGERLEFT].first) && (ITEM_ID_INVALID != axisitems[SDL_CONTROLLER_AXIS_TRIGGERRIGHT].first))
+ {
+ assignments.emplace_back(
+ IPT_AD_STICK_Z,
+ SEQ_TYPE_STANDARD,
+ input_seq(
+ make_code(ITEM_CLASS_ABSOLUTE, ITEM_MODIFIER_NONE, axisitems[SDL_CONTROLLER_AXIS_TRIGGERLEFT].first),
+ make_code(ITEM_CLASS_ABSOLUTE, ITEM_MODIFIER_REVERSE, axisitems[SDL_CONTROLLER_AXIS_TRIGGERRIGHT].first)));
+ }
+ else if (add_axis_inc_dec_assignment(assignments, IPT_AD_STICK_Z, buttonitems[SDL_CONTROLLER_BUTTON_LEFTSHOULDER], buttonitems[SDL_CONTROLLER_BUTTON_RIGHTSHOULDER]))
+ {
+ // took shoulder buttons
+ }
+ else if (add_axis_inc_dec_assignment(assignments, IPT_AD_STICK_Z, axisitems[SDL_CONTROLLER_AXIS_TRIGGERLEFT].second, axisitems[SDL_CONTROLLER_AXIS_TRIGGERRIGHT].second))
+ {
+ // took trigger buttons
+ }
+ else if (add_axis_inc_dec_assignment(assignments, IPT_AD_STICK_Z, buttonitems[SDL_CONTROLLER_BUTTON_PADDLE1], buttonitems[SDL_CONTROLLER_BUTTON_PADDLE2]))
+ {
+ // took P1/P2
+ }
+ else if (add_axis_inc_dec_assignment(assignments, IPT_AD_STICK_Z, buttonitems[SDL_CONTROLLER_BUTTON_PADDLE3], buttonitems[SDL_CONTROLLER_BUTTON_PADDLE4]))
+ {
+ // took P3/P4
+ }
+ }
+
+ // prefer trigger axes for pedals, otherwise take half axes and buttons
+ unsigned pedalbutton = 0;
+ if (!add_assignment(assignments, IPT_PEDAL, SEQ_TYPE_STANDARD, ITEM_CLASS_ABSOLUTE, ITEM_MODIFIER_NEG, { axisitems[SDL_CONTROLLER_AXIS_TRIGGERRIGHT].first }))
+ {
+ add_assignment(
+ assignments,
+ IPT_PEDAL,
+ SEQ_TYPE_STANDARD,
+ ITEM_CLASS_ABSOLUTE,
+ ITEM_MODIFIER_NEG,
+ { diraxis[1][1], diraxis[0][1] });
+ bool const incbutton = add_assignment(
+ assignments,
+ IPT_PEDAL,
+ SEQ_TYPE_INCREMENT,
+ ITEM_CLASS_SWITCH,
+ ITEM_MODIFIER_NONE,
+ { axisitems[SDL_CONTROLLER_AXIS_TRIGGERRIGHT].second, buttonitems[SDL_CONTROLLER_BUTTON_RIGHTSHOULDER] });
+ if (!incbutton)
+ {
+ if (add_assignment(assignments, IPT_PEDAL, SEQ_TYPE_INCREMENT, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, { std::get<0>(numberedbuttons[pedalbutton]) }))
+ ++pedalbutton;
+ }
+ }
+ if (!add_assignment(assignments, IPT_PEDAL2, SEQ_TYPE_STANDARD, ITEM_CLASS_ABSOLUTE, ITEM_MODIFIER_NEG, { axisitems[SDL_CONTROLLER_AXIS_TRIGGERLEFT].first }))
+ {
+ add_assignment(
+ assignments,
+ IPT_PEDAL2,
+ SEQ_TYPE_STANDARD,
+ ITEM_CLASS_ABSOLUTE,
+ ITEM_MODIFIER_POS,
+ { diraxis[1][1], diraxis[0][1] });
+ bool const incbutton = add_assignment(
+ assignments,
+ IPT_PEDAL2,
+ SEQ_TYPE_INCREMENT,
+ ITEM_CLASS_SWITCH,
+ ITEM_MODIFIER_NONE,
+ { axisitems[SDL_CONTROLLER_AXIS_TRIGGERLEFT].second, buttonitems[SDL_CONTROLLER_BUTTON_LEFTSHOULDER] });
+ if (!incbutton)
+ {
+ if (add_assignment(assignments, IPT_PEDAL2, SEQ_TYPE_INCREMENT, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, { std::get<0>(numberedbuttons[pedalbutton]) }))
+ ++pedalbutton;
+ }
+ }
+ add_assignment(assignments, IPT_PEDAL3, SEQ_TYPE_INCREMENT, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, { std::get<0>(numberedbuttons[pedalbutton]) });
+
+ // potentially use thumb sticks and/or D-pad and A/B/X/Y diamond for twin sticks
+ add_twin_stick_assignments(
+ assignments,
+ axisitems[SDL_CONTROLLER_AXIS_LEFTX].first,
+ axisitems[SDL_CONTROLLER_AXIS_LEFTY].first,
+ axisitems[SDL_CONTROLLER_AXIS_RIGHTX].first,
+ axisitems[SDL_CONTROLLER_AXIS_RIGHTY].first,
+ buttonitems[SDL_CONTROLLER_BUTTON_DPAD_LEFT],
+ buttonitems[SDL_CONTROLLER_BUTTON_DPAD_RIGHT],
+ buttonitems[SDL_CONTROLLER_BUTTON_DPAD_UP],
+ buttonitems[SDL_CONTROLLER_BUTTON_DPAD_DOWN],
+ buttonitems[SDL_CONTROLLER_BUTTON_X],
+ buttonitems[SDL_CONTROLLER_BUTTON_B],
+ buttonitems[SDL_CONTROLLER_BUTTON_Y],
+ buttonitems[SDL_CONTROLLER_BUTTON_A]);
+
+ // add assignments for buttons with fixed functions
+ add_button_assignment(assignments, IPT_SELECT, { buttonitems[SDL_CONTROLLER_BUTTON_BACK] });
+ add_button_assignment(assignments, IPT_START, { buttonitems[SDL_CONTROLLER_BUTTON_START] });
+ add_button_assignment(assignments, IPT_UI_MENU, { buttonitems[SDL_CONTROLLER_BUTTON_GUIDE] });
+
+ // the first button is always UI select
+ if (add_button_assignment(assignments, IPT_UI_SELECT, { std::get<0>(numberedbuttons[0]) }))
+ {
+ if (SDL_CONTROLLER_BUTTON_INVALID != std::get<1>(numberedbuttons[0]))
+ buttonitems[std::get<1>(numberedbuttons[0])] = ITEM_ID_INVALID;
+ if (SDL_CONTROLLER_AXIS_INVALID != std::get<2>(numberedbuttons[0]))
+ axisitems[std::get<2>(numberedbuttons[0])].second = ITEM_ID_INVALID;
+ }
+
+ // try to get a matching pair of buttons for previous/next group
+ if (consume_button_pair(assignments, IPT_UI_PREV_GROUP, IPT_UI_NEXT_GROUP, axisitems[SDL_CONTROLLER_AXIS_TRIGGERLEFT].second, axisitems[SDL_CONTROLLER_AXIS_TRIGGERRIGHT].second))
+ {
+ // took digital triggers
+ }
+ else if (!avoidpaddles && consume_button_pair(assignments, IPT_UI_PREV_GROUP, IPT_UI_NEXT_GROUP, buttonitems[SDL_CONTROLLER_BUTTON_PADDLE1], buttonitems[SDL_CONTROLLER_BUTTON_PADDLE2]))
+ {
+ // took upper paddles
+ }
+ else if (consume_trigger_pair(assignments, IPT_UI_PREV_GROUP, IPT_UI_NEXT_GROUP, axisitems[SDL_CONTROLLER_AXIS_TRIGGERLEFT].first, axisitems[SDL_CONTROLLER_AXIS_TRIGGERRIGHT].first))
+ {
+ // took analog triggers
+ }
+ else if (!avoidpaddles && consume_button_pair(assignments, IPT_UI_PREV_GROUP, IPT_UI_NEXT_GROUP, buttonitems[SDL_CONTROLLER_BUTTON_PADDLE3], buttonitems[SDL_CONTROLLER_BUTTON_PADDLE4]))
+ {
+ // took lower paddles
+ }
+ else if (consume_axis_pair(assignments, IPT_UI_PREV_GROUP, IPT_UI_NEXT_GROUP, diraxis[1][1]))
+ {
+ // took secondary Y
+ }
+ else if (consume_axis_pair(assignments, IPT_UI_PREV_GROUP, IPT_UI_NEXT_GROUP, diraxis[1][0]))
+ {
+ // took secondary X
+ }
+
+ // try to get a matching pair of buttons for page up/down
+ if (!avoidpaddles && consume_button_pair(assignments, IPT_UI_PAGE_UP, IPT_UI_PAGE_DOWN, buttonitems[SDL_CONTROLLER_BUTTON_PADDLE1], buttonitems[SDL_CONTROLLER_BUTTON_PADDLE2]))
+ {
+ // took upper paddles
+ }
+ else if (!avoidpaddles && consume_button_pair(assignments, IPT_UI_PAGE_UP, IPT_UI_PAGE_DOWN, buttonitems[SDL_CONTROLLER_BUTTON_PADDLE3], buttonitems[SDL_CONTROLLER_BUTTON_PADDLE4]))
+ {
+ // took lower paddles
+ }
+ else
+ if (consume_trigger_pair(assignments, IPT_UI_PAGE_UP, IPT_UI_PAGE_DOWN, axisitems[SDL_CONTROLLER_AXIS_TRIGGERLEFT].first, axisitems[SDL_CONTROLLER_AXIS_TRIGGERRIGHT].first))
+ {
+ // took analog triggers
+ }
+ else if (consume_axis_pair(assignments, IPT_UI_PAGE_UP, IPT_UI_PAGE_DOWN, diraxis[1][1]))
+ {
+ // took secondary Y
+ }
+
+ // try to assign X button to UI clear
+ if (add_button_assignment(assignments, IPT_UI_CLEAR, { buttonitems[SDL_CONTROLLER_BUTTON_X] }))
+ {
+ buttonitems[SDL_CONTROLLER_BUTTON_X] = ITEM_ID_INVALID;
+ }
+ else
+ {
+ // otherwise try to find an unassigned button
+ for (auto [item, button, axis] : numberedbuttons)
+ {
+ if ((SDL_CONTROLLER_BUTTON_INVALID != button) && (ITEM_ID_INVALID != buttonitems[button]))
+ {
+ add_button_assignment(assignments, IPT_UI_CLEAR, { item });
+ buttonitems[button] = ITEM_ID_INVALID;
+ break;
+ }
+ else if ((SDL_CONTROLLER_AXIS_INVALID != axis) && (ITEM_ID_INVALID != axisitems[axis].second))
+ {
+ add_button_assignment(assignments, IPT_UI_CLEAR, { item });
+ axisitems[axis].second = ITEM_ID_INVALID;
+ break;
+ }
+ }
+ }
+
+ // try to assign B button to UI back
+ if (add_button_assignment(assignments, IPT_UI_BACK, { buttonitems[SDL_CONTROLLER_BUTTON_B] }))
+ {
+ buttonitems[SDL_CONTROLLER_BUTTON_X] = ITEM_ID_INVALID;
+ }
+ else
+ {
+ // otherwise try to find an unassigned button
+ for (auto [item, button, axis] : numberedbuttons)
+ {
+ if ((SDL_CONTROLLER_BUTTON_INVALID != button) && (ITEM_ID_INVALID != buttonitems[button]))
+ {
+ add_button_assignment(assignments, IPT_UI_CLEAR, { item });
+ buttonitems[button] = ITEM_ID_INVALID;
+ break;
+ }
+ else if ((SDL_CONTROLLER_AXIS_INVALID != axis) && (ITEM_ID_INVALID != axisitems[axis].second))
+ {
+ add_button_assignment(assignments, IPT_UI_CLEAR, { item });
+ axisitems[axis].second = ITEM_ID_INVALID;
+ break;
+ }
+ }
+ }
+
+ // try to assign Y button to UI help
+ if (add_button_assignment(assignments, IPT_UI_HELP, { buttonitems[SDL_CONTROLLER_BUTTON_Y] }))
+ {
+ buttonitems[SDL_CONTROLLER_BUTTON_Y] = ITEM_ID_INVALID;
+ }
+ else
+ {
+ // otherwise try to find an unassigned button
+ for (auto [item, button, axis] : numberedbuttons)
+ {
+ if ((SDL_CONTROLLER_BUTTON_INVALID != button) && (ITEM_ID_INVALID != buttonitems[button]))
+ {
+ add_button_assignment(assignments, IPT_UI_HELP, { item });
+ buttonitems[button] = ITEM_ID_INVALID;
+ break;
+ }
+ else if ((SDL_CONTROLLER_AXIS_INVALID != axis) && (ITEM_ID_INVALID != axisitems[axis].second))
+ {
+ add_button_assignment(assignments, IPT_UI_HELP, { item });
+ axisitems[axis].second = ITEM_ID_INVALID;
+ break;
+ }
+ }
+ }
+
+ // put focus previous/next on the shoulder buttons if available - this can be overloaded with zoom
+ if (add_button_pair_assignment(assignments, IPT_UI_FOCUS_PREV, IPT_UI_FOCUS_NEXT, buttonitems[SDL_CONTROLLER_BUTTON_LEFTSHOULDER], buttonitems[SDL_CONTROLLER_BUTTON_RIGHTSHOULDER]))
+ {
+ // took shoulder buttons
+ }
+ else if (add_axis_pair_assignment(assignments, IPT_UI_FOCUS_PREV, IPT_UI_FOCUS_NEXT, diraxis[1][0]))
+ {
+ // took secondary X
+ }
+ else if (add_axis_pair_assignment(assignments, IPT_UI_FOCUS_PREV, IPT_UI_FOCUS_NEXT, diraxis[1][1]))
+ {
+ // took secondary Y
+ }
+
+ // put zoom on the secondary stick if available, or fall back to shoulder buttons
+ if (add_axis_pair_assignment(assignments, IPT_UI_ZOOM_OUT, IPT_UI_ZOOM_IN, diraxis[1][0]))
+ {
+ // took secondary X
+ if (axisitems[SDL_CONTROLLER_AXIS_LEFTX].first == diraxis[1][0])
+ add_button_assignment(assignments, IPT_UI_ZOOM_DEFAULT, { buttonitems[SDL_CONTROLLER_BUTTON_LEFTSTICK] });
+ else if (axisitems[SDL_CONTROLLER_AXIS_RIGHTX].first == diraxis[1][0])
+ add_button_assignment(assignments, IPT_UI_ZOOM_DEFAULT, { buttonitems[SDL_CONTROLLER_BUTTON_RIGHTSTICK] });
+ diraxis[1][0] = ITEM_ID_INVALID;
+ }
+ else if (add_axis_pair_assignment(assignments, IPT_UI_ZOOM_IN, IPT_UI_ZOOM_OUT, diraxis[1][1]))
+ {
+ // took secondary Y
+ if (axisitems[SDL_CONTROLLER_AXIS_LEFTY].first == diraxis[1][1])
+ add_button_assignment(assignments, IPT_UI_ZOOM_DEFAULT, { buttonitems[SDL_CONTROLLER_BUTTON_LEFTSTICK] });
+ else if (axisitems[SDL_CONTROLLER_AXIS_RIGHTY].first == diraxis[1][1])
+ add_button_assignment(assignments, IPT_UI_ZOOM_DEFAULT, { buttonitems[SDL_CONTROLLER_BUTTON_RIGHTSTICK] });
+ diraxis[1][1] = ITEM_ID_INVALID;
+ }
+ else if (consume_button_pair(assignments, IPT_UI_ZOOM_OUT, IPT_UI_ZOOM_IN, buttonitems[SDL_CONTROLLER_BUTTON_LEFTSHOULDER], buttonitems[SDL_CONTROLLER_BUTTON_RIGHTSHOULDER]))
+ {
+ // took shoulder buttons
+ }
+
+ // set default assignments
+ device.set_default_assignments(std::move(assignments));
}
- void exit() override
+ virtual void reset() override
{
- // unsubscribe for events
- sdl_event_manager::instance().unsubscribe(this);
+ sdl_joystick_device_base::reset();
+ clear_buffer();
+ }
+
+ virtual void process_event(SDL_Event const &event) override
+ {
+ if (!m_ctrldevice)
+ return;
+
+ switch (event.type)
+ {
+ case SDL_CONTROLLERAXISMOTION:
+ if (event.caxis.axis < SDL_CONTROLLER_AXIS_MAX)
+ {
+ switch (event.caxis.axis)
+ {
+ case SDL_CONTROLLER_AXIS_TRIGGERLEFT: // MAME wants negative values for triggers
+ case SDL_CONTROLLER_AXIS_TRIGGERRIGHT:
+ m_controller.axes[event.caxis.axis] = -normalize_absolute_axis(event.caxis.value, -32'767, 32'767);
+ break;
+ default:
+ m_controller.axes[event.caxis.axis] = normalize_absolute_axis(event.caxis.value, -32'767, 32'767);
+ }
+ }
+ break;
- input_module_base::exit();
+ case SDL_CONTROLLERBUTTONDOWN:
+ case SDL_CONTROLLERBUTTONUP:
+ if (event.cbutton.button < SDL_CONTROLLER_BUTTON_MAX)
+ m_controller.buttons[event.cbutton.button] = (event.cbutton.state == SDL_PRESSED) ? 0x80 : 0x00;
+ break;
+
+ case SDL_CONTROLLERDEVICEREMOVED:
+ osd_printf_verbose("Game Controller: %s [ID %s] disconnected\n", name(), id());
+ clear_instance();
+ clear_buffer();
+ close_device();
+ break;
+ }
}
- void before_poll(running_machine& machine) override
+ void attach_device(SDL_GameController *ctrl)
{
- // Tell the event manager to process events and push them to the devices
- sdl_event_manager::instance().process_events(machine);
+ 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());
}
- bool should_poll_devices(running_machine& machine) override
+private:
+ // state information for a game controller
+ struct sdl_controller_state
{
- return sdl_event_manager::instance().has_focus() && input_enabled();
+ s32 axes[SDL_CONTROLLER_AXIS_MAX];
+ s32 buttons[SDL_CONTROLLER_BUTTON_MAX];
+ };
+
+ sdl_controller_state m_controller;
+ SDL_GameController *m_ctrldevice;
+
+ void clear_buffer()
+ {
+ memset(&m_controller, 0, sizeof(m_controller));
}
- void handle_event(SDL_Event &sdlevent) override
+ void close_device()
{
- // By default dispatch event to every device
- devicelist()->for_each_device([&sdlevent](auto device) {
- downcast<sdl_device*>(device)->queue_events(&sdlevent, 1);
- });
+ if (m_ctrldevice)
+ {
+ SDL_GameControllerClose(m_ctrldevice);
+ m_ctrldevice = nullptr;
+ }
}
};
+
//============================================================
-// sdl_keyboard_module
+// sdl_input_module
//============================================================
-class sdl_keyboard_module : public sdl_input_module
+template <typename Info>
+class sdl_input_module :
+ public input_module_impl<Info, sdl_osd_interface>,
+ protected sdl_event_manager::subscriber
{
- keyboard_trans_table * m_key_trans_table;
public:
- sdl_keyboard_module()
- : sdl_input_module(OSD_KEYBOARDINPUT_PROVIDER), m_key_trans_table(nullptr)
+ sdl_input_module(char const *type, char const *name) :
+ input_module_impl<Info, sdl_osd_interface>(type, name)
{
}
- void input_init(running_machine &machine) override
+ virtual void exit() override
{
- sdl_input_module::input_init(machine);
+ // unsubscribe for events
+ unsubscribe();
- static int event_types[] = {
- static_cast<int>(SDL_KEYDOWN),
- static_cast<int>(SDL_KEYUP),
- static_cast<int>(SDL_TEXTINPUT)
- };
+ input_module_impl<Info, sdl_osd_interface>::exit();
+ }
- sdl_event_manager::instance().subscribe(event_types, ARRAY_LENGTH(event_types), this);
+protected:
+ virtual void handle_event(SDL_Event const &event) override
+ {
+ // dispatch event to every device by default
+ this->devicelist().for_each_device(
+ [&event] (auto &device) { device.queue_events(&event, 1); });
+ }
+};
- sdl_keyboard_device *devinfo;
- // Read our keymap and store a pointer to our table
- m_key_trans_table = sdlinput_read_keymap(machine);
+//============================================================
+// sdl_keyboard_module
+//============================================================
- keyboard_trans_table& local_table = *m_key_trans_table;
+class sdl_keyboard_module : public sdl_input_module<sdl_keyboard_device>
+{
+public:
+ sdl_keyboard_module() :
+ sdl_input_module<sdl_keyboard_device>(OSD_KEYBOARDINPUT_PROVIDER, "sdl")
+ {
+ }
- osd_printf_verbose("Keyboard: Start initialization\n");
+ virtual void input_init(running_machine &machine) override
+ {
+ sdl_input_module<sdl_keyboard_device>::input_init(machine);
- // SDL only has 1 keyboard add it now
- devinfo = devicelist()->create_device<sdl_keyboard_device>(machine, "System keyboard", "System keyboard", *this);
+ constexpr int event_types[] = {
+ int(SDL_KEYDOWN),
+ int(SDL_KEYUP) };
- // populate it
- for (int keynum = 0; local_table[keynum].mame_key != ITEM_ID_INVALID; keynum++)
- {
- input_item_id itemid = local_table[keynum].mame_key;
+ subscribe(osd(), event_types);
+
+ // Read our keymap and store a pointer to our table
+ sdlinput_read_keymap();
- // generate the default / modified name
- char defname[20];
- snprintf(defname, sizeof(defname) - 1, "%s", local_table[keynum].ui_name);
+ osd_printf_verbose("Keyboard: Start initialization\n");
- devinfo->device()->add_item(defname, itemid, generic_button_get_state<std::int32_t>, &devinfo->keyboard.state[local_table[keynum].sdl_scancode]);
- }
+ // SDL only has 1 keyboard add it now
+ auto &devinfo = create_device<sdl_keyboard_device>(
+ DEVICE_CLASS_KEYBOARD,
+ "System keyboard",
+ "System keyboard",
+ *m_key_trans_table);
- osd_printf_verbose("Keyboard: Registered %s\n", devinfo->name());
+ osd_printf_verbose("Keyboard: Registered %s\n", devinfo.name());
osd_printf_verbose("Keyboard: End initialization\n");
}
private:
- static keyboard_trans_table* sdlinput_read_keymap(running_machine &machine)
+ void sdlinput_read_keymap()
{
- char *keymap_filename;
- FILE *keymap_file;
- int line = 1;
- int sdl2section = 0;
-
keyboard_trans_table &default_table = keyboard_trans_table::instance();
- if (!machine.options().bool_value(SDLOPTION_KEYMAP))
- return &default_table;
-
- keymap_filename = (char *)downcast<sdl_options &>(machine.options()).keymap_file();
- osd_printf_verbose("Keymap: Start reading keymap_file %s\n", keymap_filename);
-
- keymap_file = fopen(keymap_filename, "r");
- if (keymap_file == nullptr)
- {
- osd_printf_warning("Keymap: Unable to open keymap %s, using default\n", keymap_filename);
- return &default_table;
- }
-
// Allocate a block of translation entries big enough to hold what's in the default table
- auto key_trans_entries = std::make_unique<key_trans_entry[]>(default_table.size());
+ auto key_trans_entries = std::make_unique<key_trans_entry []>(default_table.size());
- // copy the elements from the default table
+ // copy the elements from the default table and ask SDL for key names
for (int i = 0; i < default_table.size(); i++)
+ {
key_trans_entries[i] = default_table[i];
+ char const *const name = SDL_GetScancodeName(SDL_Scancode(default_table[i].sdl_scancode));
+ if (name && *name)
+ key_trans_entries[i].ui_name = name;
+ }
// Allocate the trans table to be associated with the machine so we don't have to free it
- keyboard_trans_table *custom_table = auto_alloc(machine, keyboard_trans_table(std::move(key_trans_entries), default_table.size()));
+ m_key_trans_table = std::make_unique<keyboard_trans_table>(std::move(key_trans_entries), default_table.size());
+
+ if (!options()->bool_value(SDLOPTION_KEYMAP))
+ return;
+
+ const char *const keymap_filename = dynamic_cast<sdl_options const &>(*options()).keymap_file();
+ osd_printf_verbose("Keymap: Start reading keymap_file %s\n", keymap_filename);
+
+ FILE *const keymap_file = fopen(keymap_filename, "r");
+ if (!keymap_file)
+ {
+ osd_printf_warning("Keymap: Unable to open keymap %s, using default\n", keymap_filename);
+ return;
+ }
+ int line = 1;
+ int sdl2section = 0;
while (!feof(keymap_file))
{
char buf[256];
@@ -864,34 +2266,36 @@ private:
if (sk >= 0 && index >= 0)
{
- key_trans_entry &entry = (*custom_table)[index];
+ key_trans_entry &entry = (*m_key_trans_table)[index];
entry.sdl_scancode = sk;
- entry.ui_name = auto_alloc_array(machine, char, strlen(kns) + 1);
- strcpy(entry.ui_name, kns);
+ entry.ui_name = const_cast<char *>(m_ui_names.emplace_back(kns).c_str());
osd_printf_verbose("Keymap: Mapped <%s> to <%s> with ui-text <%s>\n", sks, mks, kns);
}
else
+ {
osd_printf_error("Keymap: Error on line %d - %s key not found: %s\n", line, (sk<0) ? "sdl" : "mame", buf);
+ }
}
}
line++;
}
fclose(keymap_file);
osd_printf_verbose("Keymap: Processed %d lines\n", line);
-
- return custom_table;
}
+
+ std::unique_ptr<keyboard_trans_table> m_key_trans_table;
+ std::list<std::string> m_ui_names;
};
+
//============================================================
// sdl_mouse_module
//============================================================
-class sdl_mouse_module : public sdl_input_module
+class sdl_mouse_module : public sdl_input_module<sdl_mouse_device>
{
public:
- sdl_mouse_module()
- : sdl_input_module(OSD_MOUSEINPUT_PROVIDER)
+ sdl_mouse_module() : sdl_input_module<sdl_mouse_device>(OSD_MOUSEINPUT_PROVIDER, "sdl")
{
}
@@ -899,285 +2303,578 @@ 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)
- };
-
- sdl_event_manager::instance().subscribe(event_types, ARRAY_LENGTH(event_types), this);
+ constexpr int event_types[] = {
+ int(SDL_MOUSEMOTION),
+ int(SDL_MOUSEBUTTONDOWN),
+ int(SDL_MOUSEBUTTONUP),
+ int(SDL_MOUSEWHEEL) };
- sdl_mouse_device *devinfo;
- char defname[20];
- int button;
+ subscribe(osd(), event_types);
osd_printf_verbose("Mouse: Start initialization\n");
// SDL currently only supports one mouse
- 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);
- devinfo->device()->add_item("Y", ITEM_ID_YAXIS, generic_axis_get_state<std::int32_t>, &devinfo->mouse.lY);
+ auto &devinfo = create_device<sdl_mouse_device>(
+ DEVICE_CLASS_MOUSE,
+ "System mouse",
+ "System mouse");
- for (button = 0; button < 4; button++)
- {
- input_item_id itemid = (input_item_id)(ITEM_ID_BUTTON1 + button);
- snprintf(defname, sizeof(defname), "B%d", button + 1);
-
- devinfo->device()->add_item(defname, itemid, generic_button_get_state<std::int32_t>, &devinfo->mouse.buttons[button]);
- }
-
- osd_printf_verbose("Mouse: Registered %s\n", devinfo->name());
+ osd_printf_verbose("Mouse: Registered %s\n", devinfo.name());
osd_printf_verbose("Mouse: End initialization\n");
}
};
-static void devmap_register(device_map_t &devmap, int physical_idx, const std::string &name)
-{
- // Attempt to find the entry by name
- auto entry = std::find_if(std::begin(devmap.map), std::end(devmap.map), [&name](auto &item)
- {
- return item.name == name && item.physical < 0;
- });
+//============================================================
+// sdl_lightgun_module
+//============================================================
- // If we didn't find it by name, find the first free slot
- if (entry == std::end(devmap.map))
+class sdl_lightgun_module : public sdl_input_module<sdl_mouse_device_base>
+{
+public:
+ sdl_lightgun_module() : sdl_input_module<sdl_mouse_device_base>(OSD_LIGHTGUNINPUT_PROVIDER, "sdl")
{
- entry = std::find_if(std::begin(devmap.map), std::end(devmap.map), [](auto &item) { return item.name.empty(); });
}
- if (entry != std::end(devmap.map))
+ virtual void input_init(running_machine &machine) override
{
- entry->physical = physical_idx;
- entry->name = name;
- int logical_idx = std::distance(std::begin(devmap.map), entry);
- devmap.logical[physical_idx] = logical_idx;
+ auto &sdlopts = dynamic_cast<sdl_options const &>(*options());
+ sdl_input_module::input_init(machine);
+ bool const dual(sdlopts.dual_lightgun());
+
+ if (!dual)
+ {
+ constexpr int event_types[] = {
+ int(SDL_MOUSEMOTION),
+ int(SDL_MOUSEBUTTONDOWN),
+ int(SDL_MOUSEBUTTONUP),
+ int(SDL_MOUSEWHEEL),
+ int(SDL_WINDOWEVENT) };
+ subscribe(osd(), event_types);
+ }
+ else
+ {
+ constexpr int event_types[] = {
+ int(SDL_MOUSEBUTTONDOWN),
+ int(SDL_MOUSEBUTTONUP) };
+ subscribe(osd(), event_types);
+ }
+
+ osd_printf_verbose("Lightgun: Start initialization\n");
+
+ if (!dual)
+ {
+ auto &devinfo = create_device<sdl_lightgun_device>(
+ DEVICE_CLASS_LIGHTGUN,
+ "System pointer gun 1",
+ "System pointer gun 1");
+ osd_printf_verbose("Lightgun: Registered %s\n", devinfo.name());
+ }
+ else
+ {
+ auto &dev1info = create_device<sdl_dual_lightgun_device>(
+ DEVICE_CLASS_LIGHTGUN,
+ "System pointer gun 1",
+ "System pointer gun 1",
+ 0);
+ osd_printf_verbose("Lightgun: Registered %s\n", dev1info.name());
+
+ auto &dev2info = create_device<sdl_dual_lightgun_device>(
+ DEVICE_CLASS_LIGHTGUN,
+ "System pointer gun 2",
+ "System pointer gun 2",
+ 1);
+ osd_printf_verbose("Lightgun: Registered %s\n", dev2info.name());
+ }
+
+ osd_printf_verbose("Lightgun: End initialization\n");
}
-}
+};
+
//============================================================
-// sdl_joystick_module
+// sdl_joystick_module_base
//============================================================
-class sdl_joystick_module : public sdl_input_module
+class sdl_joystick_module_base : public sdl_input_module<sdl_joystick_device_base>
{
-private:
- device_map_t m_joy_map;
- bool m_initialized_joystick;
- bool m_initialized_haptic;
- bool m_sixaxis_mode;
-public:
- sdl_joystick_module()
- : sdl_input_module(OSD_JOYSTICKINPUT_PROVIDER), m_initialized_joystick(false), m_initialized_haptic(false), m_sixaxis_mode(false)
+protected:
+ sdl_joystick_module_base(char const *name) :
+ sdl_input_module<sdl_joystick_device_base>(OSD_JOYSTICKINPUT_PROVIDER, name),
+ m_initialized_joystick(false),
+ m_initialized_haptic(false)
{
}
- virtual void exit() override
+ virtual ~sdl_joystick_module_base()
+ {
+ 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()
{
- sdl_input_module::exit();
+ 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)
{
SDL_QuitSubSystem(SDL_INIT_JOYSTICK);
+ m_initialized_joystick = false;
}
if (m_initialized_haptic)
{
SDL_QuitSubSystem(SDL_INIT_HAPTIC);
+ m_initialized_haptic = false;
}
}
- virtual void input_init(running_machine &machine) override
+ sdl_joystick_device *create_joystick_device(int index, bool sixaxis)
{
- SDL_SetHint(SDL_HINT_ACCELEROMETER_AS_JOYSTICK, "0");
-
- m_initialized_joystick = !SDL_InitSubSystem(SDL_INIT_JOYSTICK);
- if (!m_initialized_joystick)
+ // open the joystick device
+ SDL_Joystick *const joy = SDL_JoystickOpen(index);
+ if (!joy)
{
- osd_printf_error("Could not initialize SDL Joystick: %s.\n", SDL_GetError());
- return;
+ osd_printf_error("Joystick: Could not open SDL joystick %d: %s.\n", index, SDL_GetError());
+ return nullptr;
}
- m_initialized_haptic = !SDL_InitSubSystem(SDL_INIT_HAPTIC);
- if (!m_initialized_haptic)
+ // 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 *const serial = SDL_JoystickGetSerial(joy);
+ std::string id(guid_str);
+ if (serial)
+ id.append(1, '-').append(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 (SDL_JoystickNumButtons(joy) > MAX_BUTTONS)
+ osd_printf_verbose("Joystick: ... Has %d buttons which exceeds supported %d buttons\n", SDL_JoystickNumButtons(joy), MAX_BUTTONS);
+
+ // instantiate device
+ sdl_joystick_device &devinfo = sixaxis
+ ? create_device<sdl_sixaxis_joystick_device>(DEVICE_CLASS_JOYSTICK, name ? name : guid_str, guid_str, joy, serial)
+ : create_device<sdl_joystick_device>(DEVICE_CLASS_JOYSTICK, name ? name : guid_str, guid_str, joy, serial);
+
+ if (devinfo.has_haptic())
+ osd_printf_verbose("Joystick: ... Has haptic capability\n");
+ else
+ osd_printf_verbose("Joystick: ... Does not have haptic capability\n");
+
+ 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)
+ {
+ return device->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 &device : devicelist())
{
- osd_printf_verbose("Could not initialize SDL Haptic subsystem: %s.\n", SDL_GetError());
+ if (device->is_instance(instance))
+ return device.get();
}
+ return nullptr;
+ }
- sdl_input_module::input_init(machine);
+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")
+ {
+ }
- char tempname[512];
+ virtual void exit() override
+ {
+ sdl_joystick_module_base::exit();
- m_sixaxis_mode = downcast<const sdl_options*>(options())->sixaxis();
+ quit_joystick();
+ }
- devmap_init(machine, &m_joy_map, SDLOPTION_JOYINDEX, 8, "Joystick mapping");
+ virtual void input_init(running_machine &machine) override
+ {
+ auto &sdlopts = dynamic_cast<sdl_options const &>(*options());
+ bool const sixaxis_mode = sdlopts.sixaxis();
- osd_printf_verbose("Joystick: Start initialization\n");
- int physical_stick;
- for (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);
- }
+ if (!sdlopts.debug() && sdlopts.background_input())
+ SDL_SetHint(SDL_HINT_JOYSTICK_ALLOW_BACKGROUND_EVENTS, "1");
+ SDL_SetHint(SDL_HINT_ACCELEROMETER_AS_JOYSTICK, "0");
- for (int stick = 0; stick < MAX_DEVMAP_ENTRIES; stick++)
- {
- sdl_joystick_device *devinfo = create_joystick_device(machine, &m_joy_map, stick, DEVICE_CLASS_JOYSTICK);
+ init_joystick();
+ if (!have_joystick())
+ return;
- if (devinfo == nullptr)
- continue;
+ sdl_joystick_module_base::input_init(machine);
- physical_stick = m_joy_map.map[stick].physical;
- SDL_Joystick *joy = SDL_JoystickOpen(physical_stick);
- devinfo->sdl_state.device = joy;
- devinfo->sdl_state.joystick_id = SDL_JoystickInstanceID(joy);
- devinfo->sdl_state.hapdevice = SDL_HapticOpenFromJoystick(joy);
+ osd_printf_verbose("Joystick: Start initialization\n");
+ for (int physical_stick = 0; physical_stick < SDL_NumJoysticks(); physical_stick++)
+ create_joystick_device(physical_stick, sixaxis_mode);
+
+ constexpr int event_types[] = {
+ int(SDL_JOYAXISMOTION),
+ int(SDL_JOYBALLMOTION),
+ int(SDL_JOYHATMOTION),
+ int(SDL_JOYBUTTONDOWN),
+ int(SDL_JOYBUTTONUP),
+ int(SDL_JOYDEVICEADDED),
+ int(SDL_JOYDEVICEREMOVED) };
+ subscribe(osd(), event_types);
- osd_printf_verbose("Joystick: %s\n", SDL_JoystickNameForIndex(physical_stick));
- 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)
+ osd_printf_verbose("Joystick: End initialization\n");
+ }
+
+ virtual void handle_event(SDL_Event const &event) override
+ {
+ if (SDL_JOYDEVICEADDED == event.type)
+ {
+ SDL_Joystick *const joy = SDL_JoystickOpen(event.jdevice.which);
+ if (!joy)
{
- osd_printf_verbose("Joystick: ... Has haptic capability\n");
+ osd_printf_error("Joystick: Could not open SDL joystick %d: %s.\n", event.jdevice.which, SDL_GetError());
}
else
{
- osd_printf_verbose("Joystick: ... Does not have haptic capability\n");
+ SDL_JoystickGUID guid = SDL_JoystickGetGUID(joy);
+ char const *const serial = SDL_JoystickGetSerial(joy);
+ auto *const target_device = find_reconnect_match(guid, serial);
+ if (target_device)
+ {
+ auto &devinfo = dynamic_cast<sdl_joystick_device &>(*target_device);
+ devinfo.attach_device(joy);
+ }
+ else
+ {
+ SDL_JoystickClose(joy);
+ }
}
+ }
+ else
+ {
+ dispatch_joystick_event(event);
+ }
+ }
+};
- // loop over all axes
- for (int axis = 0; axis < SDL_JoystickNumAxes(joy); axis++)
- {
- input_item_id itemid;
- if (axis < INPUT_MAX_AXIS)
- itemid = (input_item_id)(ITEM_ID_XAXIS + axis);
- else if (axis < INPUT_MAX_AXIS + INPUT_MAX_ADD_ABSOLUTE)
- itemid = (input_item_id)(ITEM_ID_ADD_ABSOLUTE1 - INPUT_MAX_AXIS + axis);
- else
- itemid = ITEM_ID_OTHER_AXIS_ABSOLUTE;
+//============================================================
+// sdl_game_controller_module
+//============================================================
- snprintf(tempname, sizeof(tempname), "A%d %s", axis, devinfo->name());
- devinfo->device()->add_item(tempname, itemid, generic_axis_get_state<std::int32_t>, &devinfo->joystick.axes[axis]);
- }
+class sdl_game_controller_module : public sdl_joystick_module_base
+{
+public:
+ sdl_game_controller_module() :
+ sdl_joystick_module_base("sdlgame"),
+ m_initialized_game_controller(false)
+ {
+ }
- // loop over all buttons
- for (int button = 0; button < SDL_JoystickNumButtons(joy); button++)
- {
- input_item_id itemid;
+ virtual void exit() override
+ {
+ sdl_joystick_module_base::exit();
- devinfo->joystick.buttons[button] = 0;
+ if (m_initialized_game_controller)
+ SDL_QuitSubSystem(SDL_INIT_GAMECONTROLLER);
- if (button < INPUT_MAX_BUTTONS)
- itemid = (input_item_id)(ITEM_ID_BUTTON1 + button);
- else if (button < INPUT_MAX_BUTTONS + INPUT_MAX_ADD_SWITCH)
- itemid = (input_item_id)(ITEM_ID_ADD_SWITCH1 - INPUT_MAX_BUTTONS + button);
- else
- itemid = ITEM_ID_OTHER_SWITCH;
+ quit_joystick();
+ }
- snprintf(tempname, sizeof(tempname), "button %d", button);
- devinfo->device()->add_item(tempname, itemid, generic_button_get_state<std::int32_t>, &devinfo->joystick.buttons[button]);
- }
+ virtual void input_init(running_machine &machine) override
+ {
+ auto &sdlopts = dynamic_cast<sdl_options const &>(*options());
+ bool const sixaxis_mode = sdlopts.sixaxis();
- // loop over all hats
- for (int hat = 0; hat < SDL_JoystickNumHats(joy); hat++)
- {
- input_item_id itemid;
-
- snprintf(tempname, sizeof(tempname), "hat %d Up", hat);
- 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);
- 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);
- 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);
- 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]);
- }
+ if (!sdlopts.debug() && sdlopts.background_input())
+ SDL_SetHint(SDL_HINT_JOYSTICK_ALLOW_BACKGROUND_EVENTS, "1");
+ SDL_SetHint(SDL_HINT_ACCELEROMETER_AS_JOYSTICK, "0");
- // loop over all (track)balls
- for (int ball = 0; ball < SDL_JoystickNumBalls(joy); ball++)
- {
- int itemid;
+ init_joystick();
+ if (!have_joystick())
+ return;
- if (ball * 2 < INPUT_MAX_ADD_RELATIVE)
- itemid = ITEM_ID_ADD_RELATIVE1 + ball * 2;
+ m_initialized_game_controller = !SDL_InitSubSystem(SDL_INIT_GAMECONTROLLER);
+ if (m_initialized_game_controller)
+ {
+ char const *const mapfile = sdlopts.controller_mapping_file();
+ if (mapfile && *mapfile && std::strcmp(mapfile, OSDOPTVAL_NONE))
+ {
+ auto const count = SDL_GameControllerAddMappingsFromFile(mapfile);
+ if (0 <= count)
+ osd_printf_verbose("Game Controller: %d controller mapping(s) added from file [%s].\n", count, mapfile);
else
- itemid = ITEM_ID_OTHER_AXIS_RELATIVE;
-
- snprintf(tempname, sizeof(tempname), "R%d %s", ball * 2, devinfo->name());
- 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());
- devinfo->device()->add_item(tempname, (input_item_id)(itemid + 1), generic_axis_get_state<std::int32_t>, &devinfo->joystick.balls[ball * 2 + 1]);
+ osd_printf_error("Game Controller: Error adding mappings from file [%s]: %s.\n", mapfile, SDL_GetError());
}
}
+ else
+ {
+ osd_printf_warning("Could not initialize SDL Game Controller: %s.\n", SDL_GetError());
+ }
- 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)
- };
+ sdl_joystick_module_base::input_init(machine);
- sdl_event_manager::instance().subscribe(event_types, ARRAY_LENGTH(event_types), this);
+ osd_printf_verbose("Game Controller: Start initialization\n");
+ for (int physical_stick = 0; physical_stick < SDL_NumJoysticks(); physical_stick++)
+ {
+ // try to open as a game controller
+ SDL_GameController *ctrl = nullptr;
+ if (m_initialized_game_controller && SDL_IsGameController(physical_stick))
+ {
+ 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("Joystick: End initialization\n");
+ // fall back to joystick API if necessary
+ if (!ctrl)
+ create_joystick_device(physical_stick, sixaxis_mode);
+ else
+ create_game_controller_device(physical_stick, ctrl);
+ }
+
+ constexpr int joy_event_types[] = {
+ int(SDL_JOYAXISMOTION),
+ int(SDL_JOYBALLMOTION),
+ int(SDL_JOYHATMOTION),
+ int(SDL_JOYBUTTONDOWN),
+ int(SDL_JOYBUTTONUP),
+ int(SDL_JOYDEVICEADDED),
+ int(SDL_JOYDEVICEREMOVED) };
+ constexpr int 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) };
+ if (m_initialized_game_controller)
+ subscribe(osd(), event_types);
+ else
+ subscribe(osd(), joy_event_types);
+
+ osd_printf_verbose("Game Controller: End initialization\n");
}
- virtual void handle_event(SDL_Event &sdlevent) override
+ virtual void handle_event(SDL_Event const &event) override
{
- // Figure out which joystick this event id destined for
- auto target_device = std::find_if(devicelist()->begin(), devicelist()->end(), [&sdlevent](auto &device)
+ switch (event.type)
{
- std::unique_ptr<device_info> &ptr = device;
- return downcast<sdl_joystick_device*>(ptr.get())->sdl_state.joystick_id == sdlevent.jdevice.which;
- });
+ case SDL_JOYDEVICEADDED:
+ {
+ // make sure this isn't an event for a reconnected game controller
+ auto const controller = find_joystick(SDL_JoystickGetDeviceInstanceID(event.jdevice.which));
+ if (find_joystick(SDL_JoystickGetDeviceInstanceID(event.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 joystick, dispatch the event to the joystick
- if (target_device != devicelist()->end())
- {
- downcast<sdl_joystick_device*>((*target_device).get())->queue_events(&sdlevent, 1);
+ SDL_Joystick *const joy = SDL_JoystickOpen(event.jdevice.which);
+ if (!joy)
+ {
+ osd_printf_error("Joystick: Could not open SDL joystick %d: %s.\n", event.jdevice.which, SDL_GetError());
+ break;
+ }
+
+ SDL_JoystickGUID guid = SDL_JoystickGetGUID(joy);
+ char const *const serial = SDL_JoystickGetSerial(joy);
+ 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:
+ if (m_initialized_game_controller)
+ {
+ SDL_GameController *const ctrl = SDL_GameControllerOpen(event.cdevice.which);
+ if (!ctrl)
+ {
+ osd_printf_error("Game Controller: Could not open SDL game controller %d: %s.\n", event.cdevice.which, SDL_GetError());
+ break;
+ }
+
+ SDL_JoystickGUID guid = SDL_JoystickGetDeviceGUID(event.cdevice.which);
+ char const *const serial = SDL_GameControllerGetSerial(ctrl);
+ 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(event);
}
}
private:
- sdl_joystick_device* create_joystick_device(running_machine &machine, device_map_t *devmap, int index, input_device_class devclass)
+ sdl_game_controller_device *create_game_controller_device(int index, SDL_GameController *ctrl)
{
- char tempname[20];
-
- if (devmap->map[index].name.empty())
+ // 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 *const serial = SDL_GameControllerGetSerial(ctrl);
+ std::string id(guid_str);
+ if (serial)
+ id.append(1, '-').append(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)
{
- // only map place holders if there were mappings specified
- if (devmap->initialized)
- {
- snprintf(tempname, ARRAY_LENGTH(tempname), "NC%d", index);
- m_sixaxis_mode
- ? devicelist()->create_device<sdl_sixaxis_joystick_device>(machine, tempname, tempname, *this)
- : devicelist()->create_device<sdl_joystick_device>(machine, tempname, tempname, *this);
- }
-
- return nullptr;
+ osd_printf_verbose("Game Controller: ... mapping [%s]\n", mapping);
+ SDL_free(mapping);
+ }
+ else
+ {
+ osd_printf_verbose("Game Controller: ... no mapping\n");
}
- return m_sixaxis_mode
- ? devicelist()->create_device<sdl_sixaxis_joystick_device>(machine, devmap->map[index].name.c_str(), devmap->map[index].name.c_str(), *this)
- : devicelist()->create_device<sdl_joystick_device>(machine, devmap->map[index].name.c_str(), devmap->map[index].name.c_str(), *this);
+ // instantiate device
+ sdl_game_controller_device &devinfo = create_device<sdl_game_controller_device>(
+ DEVICE_CLASS_JOYSTICK,
+ name ? name : guid_str,
+ guid_str,
+ ctrl,
+ serial);
+ return &devinfo;
}
+
+ bool m_initialized_game_controller;
};
-#else
+} // anonymous namespace
+
+} // namespace osd
+
+
+#else // defined(SDLMAME_SDL2)
+
+namespace osd {
+
+namespace {
+
MODULE_NOT_SUPPORTED(sdl_keyboard_module, OSD_KEYBOARDINPUT_PROVIDER, "sdl")
MODULE_NOT_SUPPORTED(sdl_mouse_module, OSD_MOUSEINPUT_PROVIDER, "sdl")
-MODULE_NOT_SUPPORTED(sdl_joystick_module, OSD_JOYSTICKINPUT_PROVIDER, "sdl")
-#endif
+MODULE_NOT_SUPPORTED(sdl_lightgun_module, OSD_LIGHTGUNINPUT_PROVIDER, "sdl")
+MODULE_NOT_SUPPORTED(sdl_joystick_module, OSD_JOYSTICKINPUT_PROVIDER, "sdljoy")
+MODULE_NOT_SUPPORTED(sdl_game_controller_module, OSD_JOYSTICKINPUT_PROVIDER, "sdlgame")
+
+} // anonymous namespace
+
+} // namespace osd
+
+#endif // defined(SDLMAME_SDL2)
+
-MODULE_DEFINITION(KEYBOARDINPUT_SDL, sdl_keyboard_module)
-MODULE_DEFINITION(MOUSEINPUT_SDL, sdl_mouse_module)
-MODULE_DEFINITION(JOYSTICKINPUT_SDL, sdl_joystick_module)
+MODULE_DEFINITION(KEYBOARDINPUT_SDL, osd::sdl_keyboard_module)
+MODULE_DEFINITION(MOUSEINPUT_SDL, osd::sdl_mouse_module)
+MODULE_DEFINITION(LIGHTGUNINPUT_SDL, osd::sdl_lightgun_module)
+MODULE_DEFINITION(JOYSTICKINPUT_SDLJOY, osd::sdl_joystick_module)
+MODULE_DEFINITION(JOYSTICKINPUT_SDLGAME, osd::sdl_game_controller_module)