// license:BSD-3-Clause
// copyright-holders:Olivier Galibert, R. Belmont, Brad Hughes
//============================================================
//
// input_sdl.cpp - SDL 2.0 implementation of MAME input routines
//
// SDLMAME by Olivier Galibert and R. Belmont
//
// SixAxis info: left analog is axes 0 & 1, right analog is axes 2 & 3,
// analog L2 is axis 12 and analog L3 is axis 13
//
//============================================================
#include "input_module.h"
#include "modules/osdmodule.h"
#if defined(SDLMAME_SDL2)
// standard sdl header
#include <SDL2/SDL.h>
#include <ctype.h>
#include <stddef.h>
#include <mutex>
#include <memory>
#include <queue>
// MAME headers
#include "emu.h"
#include "osdepend.h"
#include "ui/uimain.h"
#include "uiinput.h"
#include "strconv.h"
// MAMEOS headers
#include "input_common.h"
#include "../lib/osdobj_common.h"
#include "input_sdlcommon.h"
#include "../../sdl/osdsdl.h"
#include "../../sdl/window.h"
// winnt.h defines this
#ifdef DELETE
#undef DELETE
#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)
struct key_lookup_table
{
int code;
const char *name;
};
#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[] =
{
KE7(UNKNOWN, BACKSPACE, TAB, CLEAR, RETURN, PAUSE, ESCAPE)
KE(SPACE)
KE5(COMMA, MINUS, PERIOD, SLASH, 0)
KE8(1, 2, 3, 4, 5, 6, 7, 8)
KE3(9, SEMICOLON, EQUALS)
KE5(LEFTBRACKET,BACKSLASH, RIGHTBRACKET, A, B)
KE8(C, D, E, F, G, H, I, J)
KE8(K, L, M, N, O, P, Q, R)
KE8(S, T, U, V, W, X, Y, Z)
KE8(DELETE, KP_0, KP_1, KP_2, KP_3, KP_4, KP_5, KP_6)
KE8(KP_7, KP_8, KP_9, KP_PERIOD, KP_DIVIDE, KP_MULTIPLY,KP_MINUS, KP_PLUS)
KE8(KP_ENTER, KP_EQUALS, UP, DOWN, RIGHT, LEFT, INSERT, HOME)
KE8(END, PAGEUP, PAGEDOWN, F1, F2, F3, F4, F5)
KE8(F6, F7, F8, F9, F10, F11, F12, F13)
KE8(F14, F15, NUMLOCKCLEAR, CAPSLOCK, SCROLLLOCK, RSHIFT, LSHIFT, RCTRL)
KE5(LCTRL, RALT, LALT, LGUI, RGUI)
KE8(GRAVE, LEFTBRACKET,RIGHTBRACKET, SEMICOLON, APOSTROPHE, BACKSLASH, PRINTSCREEN,MENU)
KE(UNDO)
{
-1, ""
}
};
//============================================================
// lookup_sdl_code
//============================================================
static int lookup_sdl_code(const char *scode)
{
int i = 0;
while (sdl_lookup_table[i].code >= 0)
{
if (!strcmp(scode, sdl_lookup_table[i].name))
return sdl_lookup_table[i].code;
i++;
}
return -1;
}
//============================================================
// sdl_device
//============================================================
class sdl_device : public event_based_device<SDL_Event>
{
public:
sdl_device(running_machine &machine, const char* name, input_device_class devclass, input_module &module)
: event_based_device(machine, name, devclass, module)
{
}
protected:
std::shared_ptr<sdl_window_info> focus_window()
{
return sdl_event_manager::instance().focus_window();
}
};
//============================================================
// sdl_keyboard_device
//============================================================
#define OSD_SDL_INDEX_KEYSYM(keysym) ((keysym)->scancode)
class sdl_keyboard_device : public sdl_device
{
public:
keyboard_state keyboard;
sdl_keyboard_device(running_machine &machine, const char* name, input_module &module)
: sdl_device(machine, name, DEVICE_CLASS_KEYBOARD, module),
keyboard({{0}})
{
}
void process_event(SDL_Event &sdlevent) override
{
switch (sdlevent.type)
{
case SDL_KEYDOWN:
keyboard.state[OSD_SDL_INDEX_KEYSYM(&sdlevent.key.keysym)] = 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);
break;
case SDL_KEYUP:
keyboard.state[OSD_SDL_INDEX_KEYSYM(&sdlevent.key.keysym)] = 0x00;
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)
{
unicode_char 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);
}
}
}
break;
}
}
void reset() override
{
memset(&keyboard.state, 0, sizeof(keyboard.state));
}
};
//============================================================
// sdl_mouse_device
//============================================================
class sdl_mouse_device : public sdl_device
{
public:
mouse_state mouse;
sdl_mouse_device(running_machine &machine, const char* name, input_module &module)
: sdl_device(machine, name, DEVICE_CLASS_MOUSE, module),
mouse({0})
{
}
void reset() override
{
memset(&mouse, 0, sizeof(mouse));
}
void poll() override
{
mouse.lX = 0;
mouse.lY = 0;
sdl_device::poll();
}
virtual void process_event(SDL_Event &sdlevent) override
{
switch (sdlevent.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);
}
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)
{
// FIXME Move static declaration
static osd_ticks_t last_click = 0;
static int last_x = 0;
static int last_y = 0;
int cx, cy;
osd_ticks_t click = osd_ticks() * 1000 / osd_ticks_per_second();
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);
// FIXME Parameter ?
if ((click - last_click < 250)
&& (cx >= last_x - 4 && cx <= last_x + 4)
&& (cy >= last_y - 4 && cy <= last_y + 4))
{
last_click = 0;
machine().ui_input().push_mouse_double_click_event(window->target(), cx, cy);
}
else
{
last_click = click;
last_x = cx;
last_y = cy;
}
}
}
else if (sdlevent.button.button == 3)
{
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_rdown_event(window->target(), cx, cy);
}
}
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);
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);
if (window != nullptr && window->xy_to_render_target(sdlevent.button.x, sdlevent.button.y, &cx, &cy))
{
machine().ui_input().push_mouse_rup_event(window->target(), cx, cy);
}
}
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);
break;
}
}
};
//============================================================
// sdl_joystick_device
//============================================================
// state information for a joystick
struct sdl_joystick_state
{
INT32 axes[MAX_AXES];
INT32 buttons[MAX_BUTTONS];
INT32 hatsU[MAX_HATS], hatsD[MAX_HATS], hatsL[MAX_HATS], hatsR[MAX_HATS];
INT32 balls[MAX_AXES];
};
struct sdl_api_state
{
SDL_Joystick *device;
SDL_JoystickID joystick_id;
};
class sdl_joystick_device : public sdl_device
{
public:
sdl_joystick_state joystick;
sdl_api_state sdl_state;
sdl_joystick_device(running_machine &machine, const char *name, input_module &module)
: sdl_device(machine, name, DEVICE_CLASS_JOYSTICK, module),
joystick({{0}}),
sdl_state({ nullptr })
{
}
~sdl_joystick_device()
{
if (sdl_state.device != nullptr)
{
SDL_JoystickClose(sdl_state.device);
sdl_state.device = nullptr;
}
}
void reset() override
{
memset(&joystick, 0, sizeof(joystick));
}
void process_event(SDL_Event &sdlevent) override
{
switch (sdlevent.type)
{
case SDL_JOYAXISMOTION:
joystick.axes[sdlevent.jaxis.axis] = (sdlevent.jaxis.value * 2);
break;
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;
case SDL_JOYHATMOTION:
if (sdlevent.jhat.value & SDL_HAT_UP)
{
joystick.hatsU[sdlevent.jhat.hat] = 0x80;
}
else
{
joystick.hatsU[sdlevent.jhat.hat] = 0;
}
if (sdlevent.jhat.value & SDL_HAT_DOWN)
{
joystick.hatsD[sdlevent.jhat.hat] = 0x80;
}
else
{
joystick.hatsD[sdlevent.jhat.hat] = 0;
}
if (sdlevent.jhat.value & SDL_HAT_LEFT)
{
joystick.hatsL[sdlevent.jhat.hat] = 0x80;
}
else
{
joystick.hatsL[sdlevent.jhat.hat] = 0;
}
if (sdlevent.jhat.value & SDL_HAT_RIGHT)
{
joystick.hatsR[sdlevent.jhat.hat] = 0x80;
}
else
{
joystick.hatsR[sdlevent.jhat.hat] = 0;
}
break;
case SDL_JOYBUTTONDOWN:
case SDL_JOYBUTTONUP:
joystick.buttons[sdlevent.jbutton.button] = (sdlevent.jbutton.state == SDL_PRESSED) ? 0x80 : 0;
break;
}
}
};
class sdl_sixaxis_joystick_device : public sdl_joystick_device
{
public:
sdl_sixaxis_joystick_device(running_machine &machine, const char *name, input_module &module)
: sdl_joystick_device(machine, name, module)
{
}
void process_event(SDL_Event &sdlevent) override
{
switch (sdlevent.type)
{
case SDL_JOYAXISMOTION:
{
int axis = sdlevent.jaxis.axis;
if (axis <= 3)
{
joystick.axes[sdlevent.jaxis.axis] = (sdlevent.jaxis.value * 2);
}
else
{
int magic = (sdlevent.jaxis.value / 2) + 16384;
joystick.axes[sdlevent.jaxis.axis] = magic;
}
}
break;
default:
// Call the base for other events
sdl_joystick_device::process_event(sdlevent);
break;
}
}
};
//============================================================
// sdl_input_module
//============================================================
class sdl_input_module : public input_module_base, public sdl_event_subscriber
{
public:
sdl_input_module(const char *type)
: input_module_base(type, "sdl")
{
}
void input_init(running_machine &machine) override
{
if (machine.debug_flags & DEBUG_FLAG_OSD_ENABLED)
{
osd_printf_warning("Debug Build: Disabling input grab for -debug\n");
set_mouse_enabled(false);
}
}
void exit() override
{
// unsubscribe for events
sdl_event_manager::instance().unsubscribe(this);
input_module_base::exit();
}
void before_poll(running_machine& machine) override
{
// Tell the event manager to process events and push them to the devices
sdl_event_manager::instance().process_events(machine);
}
bool should_poll_devices(running_machine& machine) override
{
return sdl_event_manager::instance().has_focus() && input_enabled();
}
virtual void handle_event(SDL_Event &sdlevent) override
{
// By default dispatch event to every device
for (int i = 0; i < devicelist()->size(); i++)
downcast<sdl_device*>(devicelist()->at(i))->queue_events(&sdlevent, 1);
}
};
//============================================================
// sdl_keyboard_module
//============================================================
class sdl_keyboard_module : public sdl_input_module
{
keyboard_trans_table * m_key_trans_table;
public:
sdl_keyboard_module()
: sdl_input_module(OSD_KEYBOARDINPUT_PROVIDER), m_key_trans_table(nullptr)
{
}
void input_init(running_machine &machine) override
{
sdl_input_module::input_init(machine);
static int event_types[] = {
static_cast<int>(SDL_KEYDOWN),
static_cast<int>(SDL_KEYUP),
static_cast<int>(SDL_TEXTINPUT)
};
sdl_event_manager::instance().subscribe(event_types, ARRAY_LENGTH(event_types), this);
sdl_keyboard_device *devinfo;
// Read our keymap and store a pointer to our table
m_key_trans_table = sdlinput_read_keymap(machine);
keyboard_trans_table& local_table = *m_key_trans_table;
osd_printf_verbose("Keyboard: Start initialization\n");
// SDL only has 1 keyboard add it now
devinfo = devicelist()->create_device<sdl_keyboard_device>(machine, "System keyboard", *this);
// populate it
for (int keynum = 0; local_table[keynum].mame_key != ITEM_ID_INVALID; keynum++)
{
input_item_id itemid = local_table[keynum].mame_key;
// generate the default / modified name
char defname[20];
snprintf(defname, sizeof(defname) - 1, "%s", local_table[keynum].ui_name);
devinfo->device()->add_item(defname, itemid, generic_button_get_state, &devinfo->keyboard.state[local_table[keynum].sdl_scancode]);
}
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)
{
char *keymap_filename;
FILE *keymap_file;
int line = 1;
int index, i, sk, vk, ak;
char buf[256];
char mks[41];
char sks[41];
char kns[41];
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());
// copy the elements from the default table
for (int i = 0; i < default_table.size(); i++)
key_trans_entries[i] = default_table[i];
// 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()));
while (!feof(keymap_file))
{
char *ret = fgets(buf, 255, keymap_file);
if (ret && buf[0] != '\n' && buf[0] != '#')
{
buf[255] = 0;
i = strlen(buf);
if (i && buf[i - 1] == '\n')
buf[i - 1] = 0;
if (strncmp(buf, "[SDL2]", 6) == 0)
{
sdl2section = 1;
}
else if (((SDLMAME_SDL2) ^ sdl2section) == 0)
{
mks[0] = 0;
sks[0] = 0;
memset(kns, 0, ARRAY_LENGTH(kns));
sscanf(buf, "%40s %40s %x %x %40c\n",
mks, sks, &vk, &ak, kns);
index = default_table.lookup_mame_index(mks);
sk = lookup_sdl_code(sks);
if (sk >= 0 && index >= 0)
{
key_trans_entry &entry = (*custom_table)[index];
entry.sdl_key = sk;
// vk and ak are not really needed
//key_trans_table[index][VIRTUAL_KEY] = vk;
//key_trans_table[index][ASCII_KEY] = ak;
entry.ui_name = auto_alloc_array(machine, char, strlen(kns) + 1);
strcpy(entry.ui_name, kns);
osd_printf_verbose("Keymap: Mapped <%s> to <%s> with ui-text <%s>\n", sks, mks, kns);
}
else
osd_printf_warning("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;
}
};
//============================================================
// sdl_mouse_module
//============================================================
class sdl_mouse_module : public sdl_input_module
{
public:
sdl_mouse_module()
: sdl_input_module(OSD_MOUSEINPUT_PROVIDER)
{
}
virtual void input_init(running_machine &machine) override
{
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);
sdl_mouse_device *devinfo;
char defname[20];
int button;
osd_printf_verbose("Mouse: Start initialization\n");
// SDL currently only supports one mouse
devinfo = devicelist()->create_device<sdl_mouse_device>(machine, "System mouse", *this);
// add the axes
devinfo->device()->add_item("X", ITEM_ID_XAXIS, generic_axis_get_state, &devinfo->mouse.lX);
devinfo->device()->add_item("Y", ITEM_ID_YAXIS, generic_axis_get_state, &devinfo->mouse.lY);
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, &devinfo->mouse.buttons[button]);
}
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)
{
int found = 0;
int stick, i;
for (i = 0; i < MAX_DEVMAP_ENTRIES; i++)
{
if (strcmp(name.c_str(), devmap->map[i].name.c_str()) == 0 && devmap->map[i].physical < 0)
{
devmap->map[i].physical = physical_idx;
found = 1;
devmap->logical[physical_idx] = i;
}
}
if (found == 0)
{
stick = devmap_leastfree(devmap);
devmap->map[stick].physical = physical_idx;
devmap->map[stick].name = name;
devmap->logical[physical_idx] = stick;
}
}
//============================================================
// sdl_joystick_module
//============================================================
class sdl_joystick_module : public sdl_input_module
{
private:
device_map_t m_joy_map;
bool m_sixaxis_mode;
public:
sdl_joystick_module()
: sdl_input_module(OSD_JOYSTICKINPUT_PROVIDER), m_sixaxis_mode(false)
{
}
virtual void exit() override
{
sdl_input_module::exit();
SDL_QuitSubSystem(SDL_INIT_JOYSTICK);
}
virtual void input_init(running_machine &machine) override
{
SDL_SetHint(SDL_HINT_ACCELEROMETER_AS_JOYSTICK, "0");
if (SDL_InitSubSystem(SDL_INIT_JOYSTICK))
{
osd_printf_error("Could not initialize SDL Joystick: %s.\n", SDL_GetError());
return;
}
sdl_input_module::input_init(machine);
char tempname[512];
m_sixaxis_mode = downcast<const sdl_options*>(options())->sixaxis();
devmap_init(machine, &m_joy_map, SDLOPTION_JOYINDEX, 8, "Joystick mapping");
osd_printf_verbose("Joystick: Start initialization\n");
int physical_stick;
for (physical_stick = 0; physical_stick < SDL_NumJoysticks(); physical_stick++)
{
std::string joy_name = remove_spaces(SDL_JoystickNameForIndex(physical_stick));
devmap_register(&m_joy_map, physical_stick, joy_name.c_str());
}
for (int stick = 0; stick < MAX_DEVMAP_ENTRIES; stick++)
{
sdl_joystick_device *devinfo = create_joystick_device(machine, &m_joy_map, stick, DEVICE_CLASS_JOYSTICK);
if (devinfo == nullptr)
continue;
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);
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);
// 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;
snprintf(tempname, sizeof(tempname), "A%d %s", axis, devinfo->name());
devinfo->device()->add_item(tempname, itemid, generic_axis_get_state, &devinfo->joystick.axes[axis]);
}
// loop over all buttons
for (int button = 0; button < SDL_JoystickNumButtons(joy); button++)
{
input_item_id itemid;
devinfo->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 - INPUT_MAX_BUTTONS + button);
else
itemid = ITEM_ID_OTHER_SWITCH;
snprintf(tempname, sizeof(tempname), "button %d", button);
devinfo->device()->add_item(tempname, itemid, generic_button_get_state, &devinfo->joystick.buttons[button]);
}
// 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, &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, &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, &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, &devinfo->joystick.hatsR[hat]);
}
// loop over all (track)balls
for (int ball = 0; ball < SDL_JoystickNumBalls(joy); 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 %s", ball * 2, devinfo->name());
devinfo->device()->add_item(tempname, (input_item_id)itemid, generic_axis_get_state, &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, &devinfo->joystick.balls[ball * 2 + 1]);
}
}
static int event_types[] = {
static_cast<int>(SDL_JOYAXISMOTION),
static_cast<int>(SDL_JOYBALLMOTION),
static_cast<int>(SDL_JOYHATMOTION),
static_cast<int>(SDL_JOYBUTTONDOWN),
static_cast<int>(SDL_JOYBUTTONUP)
};
sdl_event_manager::instance().subscribe(event_types, ARRAY_LENGTH(event_types), this);
osd_printf_verbose("Joystick: End initialization\n");
}
virtual void handle_event(SDL_Event &sdlevent) override
{
// Figure out which joystick this event id destined for
for (int i = 0; i < devicelist()->size(); i++)
{
auto joy = downcast<sdl_joystick_device*>(devicelist()->at(i));
// If we find a matching joystick, dispatch the event to the joystick
if (joy->sdl_state.joystick_id == sdlevent.jdevice.which)
joy->queue_events(&sdlevent, 1);
}
}
private:
sdl_joystick_device* create_joystick_device(running_machine &machine, device_map_t *devmap, int index, input_device_class devclass)
{
sdl_joystick_device *devinfo = nullptr;
char tempname[20];
if (devmap->map[index].name.length() == 0)
{
/* only map place holders if there were mappings specified is enabled */
if (devmap->initialized)
{
snprintf(tempname, ARRAY_LENGTH(tempname), "NC%d", index);
devinfo = m_sixaxis_mode
? devicelist()->create_device<sdl_sixaxis_joystick_device>(machine, tempname, *this)
: devicelist()->create_device<sdl_joystick_device>(machine, tempname, *this);
}
return nullptr;
}
else
{
devinfo = m_sixaxis_mode
? devicelist()->create_device<sdl_sixaxis_joystick_device>(machine, devmap->map[index].name.c_str(), *this)
: devicelist()->create_device<sdl_joystick_device>(machine, devmap->map[index].name.c_str(), *this);
}
return devinfo;
}
};
#else
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_DEFINITION(KEYBOARDINPUT_SDL, sdl_keyboard_module)
MODULE_DEFINITION(MOUSEINPUT_SDL, sdl_mouse_module)
MODULE_DEFINITION(JOYSTICKINPUT_SDL, sdl_joystick_module)