Skip to content

Commit

Permalink
Generalized the handling of instantaneous guide button presses so the…
Browse files Browse the repository at this point in the history
…re's a minimum of 100 ms between guide button press and release.

This happens with at least the following controllers: All Apple MFI controllers, ASUS Gamepad, XiaoMi Bluetooth Controller
  • Loading branch information
slouken committed Mar 19, 2018
1 parent d529b00 commit 8e062f6
Show file tree
Hide file tree
Showing 6 changed files with 46 additions and 14 deletions.
36 changes: 36 additions & 0 deletions src/joystick/SDL_gamecontroller.c
Expand Up @@ -25,6 +25,7 @@
#include "SDL_events.h"
#include "SDL_assert.h"
#include "SDL_hints.h"
#include "SDL_timer.h"
#include "SDL_sysjoystick.h"
#include "SDL_joystick_c.h"
#include "SDL_gamecontrollerdb.h"
Expand All @@ -38,6 +39,9 @@
#endif


/* Many controllers turn the center button into an instantaneous button press */
#define SDL_MINIMUM_GUIDE_BUTTON_DELAY_MS 100

#define SDL_CONTROLLER_PLATFORM_FIELD "platform:"

/* a list of currently opened game controllers */
Expand Down Expand Up @@ -112,6 +116,7 @@ struct _SDL_GameController
SDL_ExtendedGameControllerBind *bindings;
SDL_ExtendedGameControllerBind **last_match_axis;
Uint8 *last_hat_mask;
Uint32 guide_button_down;

struct _SDL_GameController *next; /* pointer to next game controller we have allocated */
};
Expand Down Expand Up @@ -1964,6 +1969,24 @@ SDL_PrivateGameControllerButton(SDL_GameController * gamecontroller, SDL_GameCon
}
#endif /* !SDL_EVENTS_DISABLED */

if (button == SDL_CONTROLLER_BUTTON_GUIDE) {
Uint32 now = SDL_GetTicks();
if (state == SDL_PRESSED) {
gamecontroller->guide_button_down = now;

if (gamecontroller->joystick->delayed_guide_button) {
/* Skip duplicate press */
return;
}
} else {
if (!SDL_TICKS_PASSED(now, gamecontroller->guide_button_down+SDL_MINIMUM_GUIDE_BUTTON_DELAY_MS) && !gamecontroller->joystick->force_recentering) {
gamecontroller->joystick->delayed_guide_button = SDL_TRUE;
return;
}
gamecontroller->joystick->delayed_guide_button = SDL_FALSE;
}
}

/* translate the event, if desired */
posted = 0;
#if !SDL_EVENTS_DISABLED
Expand Down Expand Up @@ -2012,4 +2035,17 @@ SDL_GameControllerEventState(int state)
#endif /* SDL_EVENTS_DISABLED */
}

void
SDL_GameControllerHandleDelayedGuideButton(SDL_Joystick *joystick)
{
SDL_GameController *controllerlist = SDL_gamecontrollers;
while (controllerlist) {
if (controllerlist->joystick == joystick) {
SDL_PrivateGameControllerButton(controllerlist, SDL_CONTROLLER_BUTTON_GUIDE, SDL_RELEASED);
break;
}
controllerlist = controllerlist->next;
}
}

/* vi: set ts=4 sw=4 expandtab: */
1 change: 0 additions & 1 deletion src/joystick/SDL_gamecontrollerdb.h
Expand Up @@ -208,7 +208,6 @@ static const char *s_ControllerMappings [] =
"03000000830500006020000010010000,iBuffalo SNES Controller,a:b1,b:b0,back:b6,dpdown:+a1,dpleft:-a0,dpright:+a0,dpup:-a1,leftshoulder:b4,rightshoulder:b5,start:b7,x:b3,y:b2,",
#endif
#if defined(__ANDROID__)
"05000000050b000000450000bf7f3f00,ASUS Gamepad,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,x:b2,y:b3,",
"050000004c05000068020000dfff3f00,PS3 Controller,a:b0,b:b1,back:b4,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b2,y:b3,",
"050000004c050000cc090000fffe3f00,PS4 Controller,a:b1,b:b17,back:b15,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b5,leftshoulder:b3,leftstick:b4,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b18,rightstick:b6,righttrigger:a4,rightx:a2,righty:a5,start:b16,x:b0,y:b2,",
"05000000de2800000511000001000000,Steam Controller,a:b0,b:b1,back:b6,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:a3,start:b7,x:b2,y:b3,",
Expand Down
4 changes: 4 additions & 0 deletions src/joystick/SDL_joystick.c
Expand Up @@ -874,6 +874,10 @@ SDL_JoystickUpdate(void)
for (joystick = SDL_joysticks; joystick; joystick = joystick->next) {
SDL_SYS_JoystickUpdate(joystick);

if (joystick->delayed_guide_button) {
SDL_GameControllerHandleDelayedGuideButton(joystick);
}

if (joystick->force_recentering) {
int i;

Expand Down
3 changes: 3 additions & 0 deletions src/joystick/SDL_joystick_c.h
Expand Up @@ -42,6 +42,9 @@ extern SDL_bool SDL_IsGameControllerNameAndGUID(const char *name, SDL_JoystickGU
/* Function to return whether a game controller should be ignored */
extern SDL_bool SDL_ShouldIgnoreGameController(const char *name, SDL_JoystickGUID guid);

/* Handle delayed guide button on a game controller */
extern void SDL_GameControllerHandleDelayedGuideButton(SDL_Joystick *joystick);

/* Internal event queueing functions */
extern void SDL_PrivateJoystickAdded(int device_index);
extern void SDL_PrivateJoystickRemoved(SDL_JoystickID device_instance);
Expand Down
1 change: 1 addition & 0 deletions src/joystick/SDL_sysjoystick.h
Expand Up @@ -63,6 +63,7 @@ struct _SDL_Joystick
int ref_count; /* Reference count for multiple opens */

SDL_bool is_game_controller;
SDL_bool delayed_guide_button; /* SDL_TRUE if this device has the guide button event delayed */
SDL_bool force_recentering; /* SDL_TRUE if this device needs to have its state reset to 0 */
SDL_JoystickPowerLevel epowerlevel; /* power level of this joystick, SDL_JOYSTICK_POWER_UNKNOWN if not supported */
struct _SDL_Joystick *next; /* pointer to next joystick we have allocated */
Expand Down
15 changes: 2 additions & 13 deletions src/joystick/iphoneos/SDL_sysjoystick.m
Expand Up @@ -31,7 +31,6 @@
#include "SDL_joystick.h"
#include "SDL_hints.h"
#include "SDL_stdinc.h"
#include "SDL_timer.h"
#include "../SDL_sysjoystick.h"
#include "../SDL_joystick_c.h"
#include "../steam/SDL_steamcontroller.h"
Expand Down Expand Up @@ -560,8 +559,6 @@ SDL_JoystickID SDL_SYS_GetInstanceIdOfDeviceIndex(int device_index)
Uint8 hatstate = SDL_HAT_CENTERED;
int i;
int updateplayerindex = 0;
const Uint8 pausebutton = joystick->nbuttons - 1; /* The pause button is always last. */
const Uint32 PAUSE_RELEASE_DELAY_MS = 100;

if (controller.extendedGamepad) {
GCExtendedGamepad *gamepad = controller.extendedGamepad;
Expand Down Expand Up @@ -650,21 +647,13 @@ SDL_JoystickID SDL_SYS_GetInstanceIdOfDeviceIndex(int device_index)
}

for (i = 0; i < joystick->hwdata->num_pause_presses; i++) {
const Uint8 pausebutton = joystick->nbuttons - 1; /* The pause button is always last. */
SDL_PrivateJoystickButton(joystick, pausebutton, SDL_PRESSED);
joystick->hwdata->pause_button_down_time = SDL_GetTicks();
if (!joystick->hwdata->pause_button_down_time) {
joystick->hwdata->pause_button_down_time = 1;
}
SDL_PrivateJoystickButton(joystick, pausebutton, SDL_RELEASED);
updateplayerindex = YES;
}
joystick->hwdata->num_pause_presses = 0;

if (joystick->hwdata->pause_button_down_time &&
SDL_TICKS_PASSED(SDL_GetTicks(), joystick->hwdata->pause_button_down_time + PAUSE_RELEASE_DELAY_MS)) {
SDL_PrivateJoystickButton(joystick, pausebutton, SDL_RELEASED);
joystick->hwdata->pause_button_down_time = 0;
}

if (updateplayerindex && controller.playerIndex == -1) {
BOOL usedPlayerIndexSlots[4] = {NO, NO, NO, NO};

Expand Down

0 comments on commit 8e062f6

Please sign in to comment.