/* joystick functions */
/* ========================================================================= */
-static SDL_Joystick *sdl_joystick[MAX_PLAYERS] = { NULL, NULL, NULL, NULL };
-static int sdl_js_axis[MAX_PLAYERS][2] = { {0, 0}, {0, 0}, {0, 0}, {0, 0} };
-static int sdl_js_button[MAX_PLAYERS][2] = { {0, 0}, {0, 0}, {0, 0}, {0, 0} };
+#if defined(TARGET_SDL2)
+static void *sdl_joystick[MAX_PLAYERS]; // game controller or joystick
+#else
+static SDL_Joystick *sdl_joystick[MAX_PLAYERS]; // only joysticks supported
+#endif
+static int sdl_js_axis_raw[MAX_PLAYERS][2];
+static int sdl_js_axis[MAX_PLAYERS][2];
+static int sdl_js_button[MAX_PLAYERS][2];
+static boolean sdl_is_controller[MAX_PLAYERS];
static boolean SDLOpenJoystick(int nr)
{
if (nr < 0 || nr > MAX_PLAYERS)
return FALSE;
- return ((sdl_joystick[nr] = SDL_JoystickOpen(nr)) == NULL ? FALSE : TRUE);
+#if defined(TARGET_SDL2)
+ sdl_is_controller[nr] = SDL_IsGameController(nr);
+#else
+ sdl_is_controller[nr] = FALSE;
+#endif
+
+#if 1
+ Error(ERR_DEBUG, "opening joystick %d (%s)",
+ nr, (sdl_is_controller[nr] ? "game controller" : "joystick"));
+#endif
+
+#if defined(TARGET_SDL2)
+ if (sdl_is_controller[nr])
+ sdl_joystick[nr] = SDL_GameControllerOpen(nr);
+ else
+ sdl_joystick[nr] = SDL_JoystickOpen(nr);
+#else
+ sdl_joystick[nr] = SDL_JoystickOpen(nr);
+#endif
+
+ return (sdl_joystick[nr] != NULL);
}
static void SDLCloseJoystick(int nr)
if (nr < 0 || nr > MAX_PLAYERS)
return;
+#if 1
+ Error(ERR_DEBUG, "closing joystick %d", nr);
+#endif
+
+#if defined(TARGET_SDL2)
+ if (sdl_is_controller[nr])
+ SDL_GameControllerClose(sdl_joystick[nr]);
+ else
+ SDL_JoystickClose(sdl_joystick[nr]);
+#else
SDL_JoystickClose(sdl_joystick[nr]);
+#endif
sdl_joystick[nr] = NULL;
+
+ sdl_js_axis_raw[nr][0] = -1;
+ sdl_js_axis_raw[nr][1] = -1;
+ sdl_js_axis[nr][0] = 0;
+ sdl_js_axis[nr][1] = 0;
+ sdl_js_button[nr][0] = 0;
+ sdl_js_button[nr][1] = 0;
}
-static boolean SDLCheckJoystickOpened(int nr)
+boolean SDLCheckJoystickOpened(int nr)
{
if (nr < 0 || nr > MAX_PLAYERS)
return FALSE;
#endif
}
+static void setJoystickAxis(int nr, int axis_id_raw, int axis_value)
+{
+#if defined(TARGET_SDL2)
+ int axis_id = (axis_id_raw == SDL_CONTROLLER_AXIS_LEFTX ||
+ axis_id_raw == SDL_CONTROLLER_AXIS_RIGHTX ? 0 :
+ axis_id_raw == SDL_CONTROLLER_AXIS_LEFTY ||
+ axis_id_raw == SDL_CONTROLLER_AXIS_RIGHTY ? 1 : -1);
+#else
+ int axis_id = axis_id_raw % 2;
+#endif
+
+ if (axis_id == -1)
+ return;
+
+ // prevent (slightly jittering, but centered) axis A from resetting axis B
+ if (ABS(axis_value) < JOYSTICK_PERCENT * JOYSTICK_MAX_AXIS_POS / 100 &&
+ axis_id_raw != sdl_js_axis_raw[nr][axis_id])
+ return;
+
+ sdl_js_axis[nr][axis_id] = axis_value;
+ sdl_js_axis_raw[nr][axis_id] = axis_id_raw;
+}
+
+static void setJoystickButton(int nr, int button_id_raw, int button_state)
+{
+#if defined(TARGET_SDL2)
+ int button_id = (button_id_raw == SDL_CONTROLLER_BUTTON_A ||
+ button_id_raw == SDL_CONTROLLER_BUTTON_X ||
+ button_id_raw == SDL_CONTROLLER_BUTTON_LEFTSHOULDER ||
+ button_id_raw == SDL_CONTROLLER_BUTTON_LEFTSTICK ||
+ button_id_raw == SDL_CONTROLLER_BUTTON_RIGHTSTICK ? 0 :
+ button_id_raw == SDL_CONTROLLER_BUTTON_B ||
+ button_id_raw == SDL_CONTROLLER_BUTTON_Y ||
+ button_id_raw == SDL_CONTROLLER_BUTTON_RIGHTSHOULDER ? 1 :
+ -1);
+
+ if (button_id_raw == SDL_CONTROLLER_BUTTON_DPAD_LEFT)
+ sdl_js_axis[nr][0] = button_state * JOYSTICK_XLEFT;
+ else if (button_id_raw == SDL_CONTROLLER_BUTTON_DPAD_RIGHT)
+ sdl_js_axis[nr][0] = button_state * JOYSTICK_XRIGHT;
+ else if (button_id_raw == SDL_CONTROLLER_BUTTON_DPAD_UP)
+ sdl_js_axis[nr][1] = button_state * JOYSTICK_YUPPER;
+ else if (button_id_raw == SDL_CONTROLLER_BUTTON_DPAD_DOWN)
+ sdl_js_axis[nr][1] = button_state * JOYSTICK_YLOWER;
+
+ if (button_id_raw == SDL_CONTROLLER_BUTTON_DPAD_LEFT ||
+ button_id_raw == SDL_CONTROLLER_BUTTON_DPAD_RIGHT ||
+ button_id_raw == SDL_CONTROLLER_BUTTON_DPAD_UP ||
+ button_id_raw == SDL_CONTROLLER_BUTTON_DPAD_DOWN)
+ sdl_js_axis_raw[nr][0] = sdl_js_axis_raw[nr][1] = -1;
+#else
+ int button_id = button_id_raw % 2;
+#endif
+
+ if (button_id == -1)
+ return;
+
+ sdl_js_button[nr][button_id] = button_state;
+}
+
void HandleJoystickEvent(Event *event)
{
switch(event->type)
{
+#if defined(TARGET_SDL2)
+ case SDL_CONTROLLERAXISMOTION:
+#if 1
+ Error(ERR_DEBUG, "SDL_CONTROLLERAXISMOTION: device %d, axis %d: %d",
+ event->caxis.which, event->caxis.axis, event->caxis.value);
+#endif
+ setJoystickAxis(event->caxis.which,
+ event->caxis.axis,
+ event->caxis.value);
+ break;
+
+ case SDL_CONTROLLERBUTTONDOWN:
+#if 1
+ Error(ERR_DEBUG, "SDL_CONTROLLERBUTTONDOWN: device %d, button %d",
+ event->cbutton.which, event->cbutton.button);
+#endif
+ setJoystickButton(event->cbutton.which,
+ event->cbutton.button,
+ TRUE);
+ break;
+
+ case SDL_CONTROLLERBUTTONUP:
+#if 1
+ Error(ERR_DEBUG, "SDL_CONTROLLERBUTTONUP: device %d, button %d",
+ event->cbutton.which, event->cbutton.button);
+#endif
+ setJoystickButton(event->cbutton.which,
+ event->cbutton.button,
+ FALSE);
+ break;
+#endif
+
case SDL_JOYAXISMOTION:
- if (event->jaxis.axis < 2)
- sdl_js_axis[event->jaxis.which][event->jaxis.axis]= event->jaxis.value;
+ if (sdl_is_controller[event->jaxis.which])
+ break;
+
+#if 1
+ Error(ERR_DEBUG, "SDL_JOYAXISMOTION: device %d, axis %d: %d",
+ event->jaxis.which, event->jaxis.axis, event->jaxis.value);
+#endif
+ if (event->jaxis.axis < 4)
+ setJoystickAxis(event->jaxis.which,
+ event->jaxis.axis,
+ event->jaxis.value);
break;
case SDL_JOYBUTTONDOWN:
- if (event->jbutton.button < 2)
- sdl_js_button[event->jbutton.which][event->jbutton.button] = TRUE;
+ if (sdl_is_controller[event->jaxis.which])
+ break;
+
+#if 1
+ Error(ERR_DEBUG, "SDL_JOYBUTTONDOWN: device %d, button %d",
+ event->jbutton.which, event->jbutton.button);
+#endif
+ if (event->jbutton.button < 4)
+ setJoystickButton(event->jbutton.which,
+ event->jbutton.button,
+ TRUE);
break;
case SDL_JOYBUTTONUP:
- if (event->jbutton.button < 2)
- sdl_js_button[event->jbutton.which][event->jbutton.button] = FALSE;
+ if (sdl_is_controller[event->jaxis.which])
+ break;
+
+#if 1
+ Error(ERR_DEBUG, "SDL_JOYBUTTONUP: device %d, button %d",
+ event->jbutton.which, event->jbutton.button);
+#endif
+ if (event->jbutton.button < 4)
+ setJoystickButton(event->jbutton.which,
+ event->jbutton.button,
+ FALSE);
break;
default:
{
static boolean sdl_joystick_subsystem_initialized = FALSE;
boolean print_warning = !sdl_joystick_subsystem_initialized;
+#if defined(TARGET_SDL2)
+ char *mappings_file = "gamecontrollerdb.txt";
+ int num_mappings;
+#endif
int i;
if (!sdl_joystick_subsystem_initialized)
{
sdl_joystick_subsystem_initialized = TRUE;
+#if defined(TARGET_SDL2)
+ SDL_SetHint(SDL_HINT_ACCELEROMETER_AS_JOYSTICK, "0");
+
+ if (SDL_InitSubSystem(SDL_INIT_GAMECONTROLLER) < 0)
+#else
if (SDL_InitSubSystem(SDL_INIT_JOYSTICK) < 0)
+#endif
{
Error(ERR_EXIT, "SDL_Init() failed: %s", SDL_GetError());
return;
}
+
+#if defined(TARGET_SDL2)
+ num_mappings = SDL_GameControllerAddMappingsFromFile(mappings_file);
+
+ if (num_mappings != -1)
+ Error(ERR_INFO, "%d game controller mapping(s) added", num_mappings);
+ else
+ Error(ERR_WARN, "no game controller mappings found");
+
+ Error(ERR_INFO, "%d joystick(s) found:", SDL_NumJoysticks());
+
+ for (i = 0; i < SDL_NumJoysticks(); i++)
+ {
+ const char *name, *type;
+
+ if (SDL_IsGameController(i))
+ {
+ name = SDL_GameControllerNameForIndex(i);
+ type = "game controller";
+ }
+ else
+ {
+ name = SDL_JoystickNameForIndex(i);
+ type = "joystick";
+ }
+
+ Error(ERR_INFO, "- joystick %d (%s): '%s'",
+ i, type, (name ? name : "(Unknown)"));
+ }
+#endif
}
+ /* assign joysticks from configured to connected joystick for all players */
for (i = 0; i < MAX_PLAYERS; i++)
{
/* get configured joystick for this player */
/* misuse joystick file descriptor variable to store joystick number */
joystick.fd[i] = joystick_nr;
+ }
- if (joystick_nr == -1)
- continue;
-
+ /* now open all connected joysticks (regardless if configured or not) */
+ for (i = 0; i < SDL_NumJoysticks(); i++)
+ {
/* this allows subsequent calls to 'InitJoysticks' for re-initialization */
- if (SDLCheckJoystickOpened(joystick_nr))
- SDLCloseJoystick(joystick_nr);
-
- if (!setup.input[i].use_joystick)
- continue;
-
- if (!SDLOpenJoystick(joystick_nr))
- {
- if (print_warning)
- Error(ERR_WARN, "cannot open joystick %d", joystick_nr);
-
- continue;
- }
+ if (SDLCheckJoystickOpened(i))
+ SDLCloseJoystick(i);
- joystick.status = JOYSTICK_ACTIVATED;
+ if (SDLOpenJoystick(i))
+ joystick.status = JOYSTICK_ACTIVATED;
+ else if (print_warning)
+ Error(ERR_WARN, "cannot open joystick %d", i);
}
}
ExpireSoundLoops(FALSE);
KeyboardAutoRepeatOn();
- ActivateJoystick();
audio.sound_deactivated = FALSE;
/* (this is needed when called from GameEnd() after winning a game) */
KeyboardAutoRepeatOn();
- ActivateJoystick();
/* (this is needed when called from GameEnd() after winning a game) */
SetDrawDeactivationMask(REDRAW_NONE);
DrawSetupScreen();
}
-#if !defined(PLATFORM_ANDROID)
static void execSetupInput()
{
setup_mode = SETUP_MODE_INPUT;
DrawSetupScreen();
}
-#endif
static void execSetupShortcuts()
{
{ TYPE_ENTER_MENU, execSetupGraphics, "Graphics" },
{ TYPE_ENTER_MENU, execSetupSound, "Sound & Music" },
{ TYPE_ENTER_MENU, execSetupArtwork, "Custom Artwork" },
-#if !defined(PLATFORM_ANDROID)
{ TYPE_ENTER_MENU, execSetupInput, "Input Devices" },
{ TYPE_ENTER_MENU, execSetupTouch, "Touch Controls" },
-#else
- { TYPE_ENTER_MENU, execSetupTouch, "Touch Controls" },
-#endif
{ TYPE_ENTER_MENU, execSetupShortcuts, "Key Shortcuts" },
{ TYPE_EMPTY, NULL, "" },
{ TYPE_LEAVE_MENU, execExitSetup, "Exit" },
DrawTextSCentered(mSY - SY + 16, FONT_TITLE_1, "Setup Input");
- DrawTextSCentered(SYSIZE - 20, FONT_TITLE_2,
- "Joysticks deactivated on this screen");
-
for (i = 0; setup_info[i].type != 0 && i < MAX_MENU_ENTRIES_ON_SCREEN; i++)
{
if (setup_info[i].type & (TYPE_ENTER_MENU|TYPE_ENTER_LIST))
};
int text_font_nr = (active ? FONT_MENU_1_ACTIVE : FONT_MENU_1);
- InitJoysticks();
-
custom_key = setup.input[player_nr].key;
DrawText(mSX + 11 * 32, mSY + 2 * 32, int2str(player_nr + 1, 1),
if (setup.input[player_nr].use_joystick)
{
char *device_name = setup.input[player_nr].joy.device_name;
- char *text = joystick_name[getJoystickNrFromDeviceName(device_name)];
- int font_nr = (joystick.fd[player_nr] < 0 ? FONT_VALUE_OLD : FONT_VALUE_1);
+ int joystick_nr = getJoystickNrFromDeviceName(device_name);
+ boolean joystick_active = CheckJoystickOpened(joystick_nr);
+ char *text = joystick_name[joystick_nr];
+ int font_nr = (joystick_active ? FONT_VALUE_1 : FONT_VALUE_OLD);
DrawText(mSX + 8 * 32, mSY + 3 * 32, text, font_nr);
DrawText(mSX + 32, mSY + 4 * 32, "Calibrate", text_font_nr);
else if (y == 2)
{
if (setup.input[input_player_nr].use_joystick)
- {
- InitJoysticks();
CalibrateJoystick(input_player_nr);
- }
else
CustomizeKeyboard(input_player_nr);
}
void DrawSetupScreen()
{
- DeactivateJoystick();
-
if (setup_mode == SETUP_MODE_INPUT)
DrawSetupScreen_Input();
else if (setup_mode == SETUP_MODE_CHOOSE_GAME_SPEED)