From 8e062f692578d3b32a516401aa732ea8fa516bc4 Mon Sep 17 00:00:00 2001 From: Sam Lantinga Date: Mon, 19 Mar 2018 14:42:51 -0700 Subject: [PATCH] Generalized the handling of instantaneous guide button presses so there'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 --- src/joystick/SDL_gamecontroller.c | 36 +++++++++++++++++++++++++ src/joystick/SDL_gamecontrollerdb.h | 1 - src/joystick/SDL_joystick.c | 4 +++ src/joystick/SDL_joystick_c.h | 3 +++ src/joystick/SDL_sysjoystick.h | 1 + src/joystick/iphoneos/SDL_sysjoystick.m | 15 ++--------- 6 files changed, 46 insertions(+), 14 deletions(-) diff --git a/src/joystick/SDL_gamecontroller.c b/src/joystick/SDL_gamecontroller.c index 3326c466fed68..cdf97e4821378 100644 --- a/src/joystick/SDL_gamecontroller.c +++ b/src/joystick/SDL_gamecontroller.c @@ -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" @@ -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 */ @@ -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 */ }; @@ -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 @@ -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: */ diff --git a/src/joystick/SDL_gamecontrollerdb.h b/src/joystick/SDL_gamecontrollerdb.h index 6f75be67698c5..5c8e768dbd6a0 100644 --- a/src/joystick/SDL_gamecontrollerdb.h +++ b/src/joystick/SDL_gamecontrollerdb.h @@ -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,", diff --git a/src/joystick/SDL_joystick.c b/src/joystick/SDL_joystick.c index 38eef7c2fa9f4..ebbd2bf9cff2f 100644 --- a/src/joystick/SDL_joystick.c +++ b/src/joystick/SDL_joystick.c @@ -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; diff --git a/src/joystick/SDL_joystick_c.h b/src/joystick/SDL_joystick_c.h index 0a8fdb455e633..2ce622eae2c00 100644 --- a/src/joystick/SDL_joystick_c.h +++ b/src/joystick/SDL_joystick_c.h @@ -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); diff --git a/src/joystick/SDL_sysjoystick.h b/src/joystick/SDL_sysjoystick.h index 0ce31154b0db8..efcc2d7b2ce59 100644 --- a/src/joystick/SDL_sysjoystick.h +++ b/src/joystick/SDL_sysjoystick.h @@ -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 */ diff --git a/src/joystick/iphoneos/SDL_sysjoystick.m b/src/joystick/iphoneos/SDL_sysjoystick.m index 71b81d3cfac62..2da1e6c2b8e6f 100644 --- a/src/joystick/iphoneos/SDL_sysjoystick.m +++ b/src/joystick/iphoneos/SDL_sysjoystick.m @@ -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" @@ -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; @@ -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};