video: Add support for SDL joysticks and game controllers.

This commit is contained in:
Lars Brinkhoff 2020-02-04 09:43:38 +01:00
parent 05e4babe24
commit 72b89054da
2 changed files with 187 additions and 0 deletions

View file

@ -37,6 +37,10 @@ t_bool vid_mouse_b1 = FALSE;
t_bool vid_mouse_b2 = FALSE; t_bool vid_mouse_b2 = FALSE;
t_bool vid_mouse_b3 = FALSE; t_bool vid_mouse_b3 = FALSE;
static VID_QUIT_CALLBACK vid_quit_callback = NULL; static VID_QUIT_CALLBACK vid_quit_callback = NULL;
static VID_GAMEPAD_CALLBACK motion_callback[10];
static VID_GAMEPAD_CALLBACK button_callback[10];
static int vid_gamepad_inited = 0;
static int vid_gamepad_ok = 0; /* Or else just joysticks. */
t_stat vid_register_quit_callback (VID_QUIT_CALLBACK callback) t_stat vid_register_quit_callback (VID_QUIT_CALLBACK callback)
{ {
@ -44,6 +48,41 @@ vid_quit_callback = callback;
return SCPE_OK; return SCPE_OK;
} }
static t_stat register_callback (void **array, int n, void *callback)
{
int i, j = -1;
if (!vid_gamepad_inited) {
return SCPE_NOATT;
}
for (i = 0; i < n; i++) {
if (array[i] == callback)
return SCPE_ALATT;
if (array[i] == NULL)
j = i;
}
if (j != -1) {
array[j] = callback;
return SCPE_OK;
}
return SCPE_NXM;
}
t_stat vid_register_gamepad_motion_callback (VID_GAMEPAD_CALLBACK callback)
{
int n = sizeof (motion_callback) / sizeof (callback);
return register_callback ((void **)motion_callback, n, (void *)callback);
}
t_stat vid_register_gamepad_button_callback (VID_GAMEPAD_CALLBACK callback)
{
int n = sizeof (button_callback) / sizeof (callback);
return register_callback ((void **)button_callback, n, (void *)callback);
}
t_stat vid_show (FILE* st, DEVICE *dptr, UNIT* uptr, int32 val, CONST char* desc) t_stat vid_show (FILE* st, DEVICE *dptr, UNIT* uptr, int32 val, CONST char* desc)
{ {
return vid_show_video (st, uptr, val, desc); return vid_show_video (st, uptr, val, desc);
@ -510,6 +549,64 @@ return SCPE_OK;
} }
#endif #endif
static t_stat vid_init_controllers (void)
{
SDL_Joystick *y;
SDL_version ver;
int i, n;
if (vid_gamepad_inited)
return SCPE_OK;
/* Chech that the SDL_GameControllerFromInstanceID function is
available at run time. */
SDL_GetVersion(&ver);
vid_gamepad_ok = (ver.major > 2 ||
(ver.major == 2 && (ver.minor > 0 || ver.patch >= 4)));
SDL_InitSubSystem(SDL_INIT_JOYSTICK);
if (vid_gamepad_ok)
SDL_InitSubSystem(SDL_INIT_GAMECONTROLLER);
if (SDL_JoystickEventState (SDL_ENABLE) < 0) {
SDL_QuitSubSystem(SDL_INIT_JOYSTICK);
SDL_QuitSubSystem(SDL_INIT_GAMECONTROLLER);
return SCPE_IOERR;
}
if (vid_gamepad_ok && SDL_GameControllerEventState (SDL_ENABLE) < 0) {
SDL_QuitSubSystem(SDL_INIT_JOYSTICK);
SDL_QuitSubSystem(SDL_INIT_GAMECONTROLLER);
return SCPE_IOERR;
}
n = SDL_NumJoysticks();
for (i = 0; i < n; i++) {
if (vid_gamepad_ok && SDL_IsGameController (i)) {
SDL_GameController *x = SDL_GameControllerOpen (i);
if (x != NULL) {
sim_debug (SIM_VID_DBG_VIDEO, vid_dev,
"Game controller: %s\n", SDL_GameControllerNameForIndex(i));
}
}
else {
y = SDL_JoystickOpen (i);
if (y != NULL) {
sim_debug (SIM_VID_DBG_VIDEO, vid_dev,
"Joystick: %s\n", SDL_JoystickNameForIndex(i));
sim_debug (SIM_VID_DBG_VIDEO, vid_dev,
"Number of axes: %d, buttons: %d\n",
SDL_JoystickNumAxes(y),
SDL_JoystickNumButtons(y));
}
}
}
vid_gamepad_inited = 1;
return SCPE_OK;
}
t_stat vid_open (DEVICE *dptr, const char *title, uint32 width, uint32 height, int flags) t_stat vid_open (DEVICE *dptr, const char *title, uint32 width, uint32 height, int flags)
{ {
if (!vid_active) { if (!vid_active) {
@ -538,10 +635,18 @@ if (!vid_active) {
vid_dev = dptr; vid_dev = dptr;
memset (motion_callback, 0, sizeof motion_callback);
memset (button_callback, 0, sizeof button_callback);
stat = vid_create_window (); stat = vid_create_window ();
if (stat != SCPE_OK) if (stat != SCPE_OK)
return stat; return stat;
if (vid_init_controllers () != SCPE_OK) {
sim_debug (SIM_VID_DBG_VIDEO, vid_dev,
"vid_open() - Failed initializing game controllers\n");
}
sim_debug (SIM_VID_DBG_VIDEO|SIM_VID_DBG_KEY|SIM_VID_DBG_MOUSE, vid_dev, "vid_open() - Success\n"); sim_debug (SIM_VID_DBG_VIDEO|SIM_VID_DBG_KEY|SIM_VID_DBG_MOUSE, vid_dev, "vid_open() - Success\n");
} }
return SCPE_OK; return SCPE_OK;
@ -553,6 +658,12 @@ if (vid_active) {
SDL_Event user_event; SDL_Event user_event;
int status; int status;
vid_gamepad_inited = 0;
memset (motion_callback, 0, sizeof motion_callback);
memset (button_callback, 0, sizeof button_callback);
SDL_QuitSubSystem(SDL_INIT_JOYSTICK);
SDL_QuitSubSystem(SDL_INIT_GAMECONTROLLER);
vid_active = FALSE; vid_active = FALSE;
if (vid_ready) { if (vid_ready) {
sim_debug (SIM_VID_DBG_VIDEO|SIM_VID_DBG_KEY|SIM_VID_DBG_MOUSE, vid_dev, "vid_close()\n"); sim_debug (SIM_VID_DBG_VIDEO|SIM_VID_DBG_KEY|SIM_VID_DBG_MOUSE, vid_dev, "vid_close()\n");
@ -1149,6 +1260,60 @@ switch (key) {
} }
} }
void vid_joy_motion (SDL_JoyAxisEvent *event)
{
int n = sizeof motion_callback / sizeof (VID_GAMEPAD_CALLBACK);
int i;
for (i = 0; i < n; i++) {
if (motion_callback[i]) {
motion_callback[i](event->which, event->axis, event->value);
}
}
}
void vid_joy_button (SDL_JoyButtonEvent *event)
{
int n = sizeof button_callback / sizeof (VID_GAMEPAD_CALLBACK);
int i;
for (i = 0; i < n; i++) {
if (button_callback[i]) {
button_callback[i](event->which, event->button, event->state);
}
}
}
void vid_controller_motion (SDL_ControllerAxisEvent *event)
{
SDL_JoyAxisEvent e;
e.which = event->which;
e.axis = event->axis;
e.value = event->value;
vid_joy_motion (&e);
}
void vid_controller_button (SDL_ControllerButtonEvent *event)
{
/* SDL_GameControllerFromInstanceID is only available from SDL
version 2.0.4, so check the version at compile time. The
version is also checked at run time. */
#if (SDL_MAJOR_VERSION > 2) || (SDL_MAJOR_VERSION == 2 && \
(SDL_MINOR_VERSION > 0) || (SDL_PATCHLEVEL >= 4))
SDL_JoyButtonEvent e;
SDL_GameControllerButtonBind b;
SDL_GameController *c;
c = SDL_GameControllerFromInstanceID (event->which);
b = SDL_GameControllerGetBindForButton (c, event->button);
e.which = event->which;
e.button = b.value.button;
e.state = event->state;
vid_joy_button (&e);
#endif
}
void vid_key (SDL_KeyboardEvent *event) void vid_key (SDL_KeyboardEvent *event)
{ {
SIM_KEY_EVENT ev; SIM_KEY_EVENT ev;
@ -1702,6 +1867,25 @@ while (vid_active) {
case SDL_MOUSEMOTION: case SDL_MOUSEMOTION:
vid_mouse_move (&event.motion); vid_mouse_move (&event.motion);
break; break;
case SDL_JOYAXISMOTION:
vid_joy_motion (&event.jaxis);
break;
case SDL_JOYBUTTONUP:
case SDL_JOYBUTTONDOWN:
vid_joy_button (&event.jbutton);
break;
case SDL_CONTROLLERAXISMOTION:
vid_controller_motion (&event.caxis);
break;
case SDL_CONTROLLERBUTTONUP:
case SDL_CONTROLLERBUTTONDOWN:
vid_controller_button (&event.cbutton);
break;
#if SDL_MAJOR_VERSION != 1 #if SDL_MAJOR_VERSION != 1
case SDL_WINDOWEVENT: case SDL_WINDOWEVENT:
if (event.window.windowID == vid_windowID) { if (event.window.windowID == vid_windowID) {

View file

@ -180,6 +180,9 @@ t_stat vid_open (DEVICE *dptr, const char *title, uint32 width, uint32 height, i
/* code responsible for cursor display in video) */ /* code responsible for cursor display in video) */
typedef void (*VID_QUIT_CALLBACK)(void); typedef void (*VID_QUIT_CALLBACK)(void);
t_stat vid_register_quit_callback (VID_QUIT_CALLBACK callback); t_stat vid_register_quit_callback (VID_QUIT_CALLBACK callback);
typedef void (*VID_GAMEPAD_CALLBACK)(int, int, int);
t_stat vid_register_gamepad_motion_callback (VID_GAMEPAD_CALLBACK);
t_stat vid_register_gamepad_button_callback (VID_GAMEPAD_CALLBACK);
t_stat vid_close (void); t_stat vid_close (void);
t_stat vid_poll_kb (SIM_KEY_EVENT *ev); t_stat vid_poll_kb (SIM_KEY_EVENT *ev);
t_stat vid_poll_mouse (SIM_MOUSE_EVENT *ev); t_stat vid_poll_mouse (SIM_MOUSE_EVENT *ev);