SDL: Fixed controller rumble on macOS

From 46869db01c1c616b6f6ab9364f18c283d57513b3 Mon Sep 17 00:00:00 2001
From: Sam Lantinga <[EMAIL REDACTED]>
Date: Mon, 26 Jul 2021 23:27:13 -0700
Subject: [PATCH] Fixed controller rumble on macOS

Needed to add a strong reference to the haptics engine
---
 src/joystick/iphoneos/SDL_mfijoystick.m | 90 ++++++++++++-------------
 1 file changed, 45 insertions(+), 45 deletions(-)

diff --git a/src/joystick/iphoneos/SDL_mfijoystick.m b/src/joystick/iphoneos/SDL_mfijoystick.m
index 9dae6f712b..2e8c137c6d 100644
--- a/src/joystick/iphoneos/SDL_mfijoystick.m
+++ b/src/joystick/iphoneos/SDL_mfijoystick.m
@@ -1019,23 +1019,23 @@ static int is_macos11(void)
 #ifdef ENABLE_MFI_RUMBLE
 
 @interface SDL_RumbleMotor : NSObject
+    @property(nonatomic,strong) CHHapticEngine *engine API_AVAILABLE(macos(11.0), ios(13.0), tvos(14.0));
+    @property(nonatomic,strong) id<CHHapticPatternPlayer> player API_AVAILABLE(macos(11.0), ios(13.0), tvos(14.0));
+    @property bool active;
 @end
 
 @implementation SDL_RumbleMotor {
-    CHHapticEngine *engine API_AVAILABLE(macos(11.0), ios(13.0), tvos(14.0));
-    id<CHHapticPatternPlayer> player API_AVAILABLE(macos(11.0), ios(13.0), tvos(14.0));
-    bool active;
 }
 
 -(void)cleanup
 {
-    if (self->player != nil) {
-        [self->player cancelAndReturnError:nil];
-        self->player = nil;
+    if (self.player != nil) {
+        [self.player cancelAndReturnError:nil];
+        self.player = nil;
     }
-    if (self->engine != nil) {
-        [self->engine stopWithCompletionHandler:nil];
-        self->engine = nil;
+    if (self.engine != nil) {
+        [self.engine stopWithCompletionHandler:nil];
+        self.engine = nil;
     }
 }
 
@@ -1043,21 +1043,21 @@ -(int)setIntensity:(float)intensity
 {
     @autoreleasepool {
         if (@available(macos 11.0, iOS 14.0, tvOS 14.0, *)) {
-            NSError *error;
+            NSError *error = nil;
 
-            if (self->engine == nil) {
+            if (self.engine == nil) {
                 return SDL_SetError("Haptics engine was stopped");
             }
 
             if (intensity == 0.0f) {
-                if (self->player && self->active) {
-                    [self->player stopAtTime:0 error:&error];
+                if (self.player && self.active) {
+                    [self.player stopAtTime:0 error:&error];
                 }
-                self->active = false;
+                self.active = false;
                 return 0;
             }
 
-            if (self->player == nil) {
+            if (self.player == nil) {
                 CHHapticEventParameter *param = [[CHHapticEventParameter alloc] initWithParameterID:CHHapticEventParameterIDHapticIntensity value:1.0f];
                 CHHapticEvent *event = [[CHHapticEvent alloc] initWithEventType:CHHapticEventTypeHapticContinuous parameters:[NSArray arrayWithObjects:param, nil] relativeTime:0 duration:GCHapticDurationInfinite];
                 CHHapticPattern *pattern = [[CHHapticPattern alloc] initWithEvents:[NSArray arrayWithObject:event] parameters:[[NSArray alloc] init] error:&error];
@@ -1065,22 +1065,22 @@ -(int)setIntensity:(float)intensity
                     return SDL_SetError("Couldn't create haptic pattern: %s", [error.localizedDescription UTF8String]);
                 }
 
-                self->player = [self->engine createPlayerWithPattern:pattern error:&error];
+                self.player = [self.engine createPlayerWithPattern:pattern error:&error];
                 if (error != nil) {
                     return SDL_SetError("Couldn't create haptic player: %s", [error.localizedDescription UTF8String]);
                 }
-                self->active = false;
+                self.active = false;
             }
 
             CHHapticDynamicParameter *param = [[CHHapticDynamicParameter alloc] initWithParameterID:CHHapticDynamicParameterIDHapticIntensityControl value:intensity relativeTime:0];
-            [self->player sendParameters:[NSArray arrayWithObject:param] atTime:0 error:&error];
+            [self.player sendParameters:[NSArray arrayWithObject:param] atTime:0 error:&error];
             if (error != nil) {
                 return SDL_SetError("Couldn't update haptic player: %s", [error.localizedDescription UTF8String]);
             }
 
-            if (!self->active) {
-                [self->player startAtTime:0 error:&error];
-                self->active = true;
+            if (!self.active) {
+                [self.player startAtTime:0 error:&error];
+                self.active = true;
             }
         }
 
@@ -1094,36 +1094,36 @@ -(id) initWithController:(GCController*)controller locality:(GCHapticsLocality)l
         self = [super init];
         NSError *error;
 
-        self->engine = [controller.haptics createEngineWithLocality:locality];
-        if (self->engine == nil) {
+        self.engine = [controller.haptics createEngineWithLocality:locality];
+        if (self.engine == nil) {
             SDL_SetError("Couldn't create haptics engine");
             return nil;
         }
 
-        [self->engine startAndReturnError:&error];
+        [self.engine startAndReturnError:&error];
         if (error != nil) {
             SDL_SetError("Couldn't start haptics engine");
             return nil;
         }
 
         __weak typeof(self) weakSelf = self;
-        self->engine.stoppedHandler = ^(CHHapticEngineStoppedReason stoppedReason) {
+        self.engine.stoppedHandler = ^(CHHapticEngineStoppedReason stoppedReason) {
             SDL_RumbleMotor *_this = weakSelf;
             if (_this == nil) {
                 return;
             }
 
-            _this->player = nil;
-            _this->engine = nil;
+            _this.player = nil;
+            _this.engine = nil;
         };
-        self->engine.resetHandler = ^{
+        self.engine.resetHandler = ^{
             SDL_RumbleMotor *_this = weakSelf;
             if (_this == nil) {
                 return;
             }
 
-            _this->player = nil;
-            [_this->engine startAndReturnError:nil];
+            _this.player = nil;
+            [_this.engine startAndReturnError:nil];
         };
 
         return self;
@@ -1133,13 +1133,13 @@ -(id) initWithController:(GCController*)controller locality:(GCHapticsLocality)l
 @end
 
 @interface SDL_RumbleContext : NSObject
+    @property(nonatomic,strong) SDL_RumbleMotor *m_low_frequency_motor;
+    @property(nonatomic,strong) SDL_RumbleMotor *m_high_frequency_motor;
+    @property(nonatomic,strong) SDL_RumbleMotor *m_left_trigger_motor;
+    @property(nonatomic,strong) SDL_RumbleMotor *m_right_trigger_motor;
 @end
 
 @implementation SDL_RumbleContext {
-    SDL_RumbleMotor *m_low_frequency_motor;
-    SDL_RumbleMotor *m_high_frequency_motor;
-    SDL_RumbleMotor *m_left_trigger_motor;
-    SDL_RumbleMotor *m_right_trigger_motor;
 }
 
 -(id) initWithLowFrequencyMotor:(SDL_RumbleMotor*)low_frequency_motor
@@ -1148,10 +1148,10 @@ -(id) initWithLowFrequencyMotor:(SDL_RumbleMotor*)low_frequency_motor
               RightTriggerMotor:(SDL_RumbleMotor*)right_trigger_motor
 {
     self = [super init];
-    self->m_low_frequency_motor = low_frequency_motor;
-    self->m_high_frequency_motor = high_frequency_motor;
-    self->m_left_trigger_motor = left_trigger_motor;
-    self->m_right_trigger_motor = right_trigger_motor;
+    self.m_low_frequency_motor = low_frequency_motor;
+    self.m_high_frequency_motor = high_frequency_motor;
+    self.m_left_trigger_motor = left_trigger_motor;
+    self.m_right_trigger_motor = right_trigger_motor;
     return self;
 }
 
@@ -1159,8 +1159,8 @@ -(int) rumbleWithLowFrequency:(Uint16)low_frequency_rumble andHighFrequency:(Uin
 {
     int result = 0;
 
-    result += [self->m_low_frequency_motor setIntensity:((float)low_frequency_rumble / 65535.0f)];
-    result += [self->m_high_frequency_motor setIntensity:((float)high_frequency_rumble / 65535.0f)];
+    result += [self.m_low_frequency_motor setIntensity:((float)low_frequency_rumble / 65535.0f)];
+    result += [self.m_high_frequency_motor setIntensity:((float)high_frequency_rumble / 65535.0f)];
     return ((result < 0) ? -1 : 0);
 }
 
@@ -1168,9 +1168,9 @@ -(int) rumbleLeftTrigger:(Uint16)left_rumble andRightTrigger:(Uint16)right_rumbl
 {
     int result = 0;
 
-    if (self->m_left_trigger_motor && self->m_right_trigger_motor) {
-        result += [self->m_left_trigger_motor setIntensity:((float)left_rumble / 65535.0f)];
-        result += [self->m_right_trigger_motor setIntensity:((float)right_rumble / 65535.0f)];
+    if (self.m_left_trigger_motor && self.m_right_trigger_motor) {
+        result += [self.m_left_trigger_motor setIntensity:((float)left_rumble / 65535.0f)];
+        result += [self.m_right_trigger_motor setIntensity:((float)right_rumble / 65535.0f)];
     } else {
         result = SDL_Unsupported();
     }
@@ -1179,8 +1179,8 @@ -(int) rumbleLeftTrigger:(Uint16)left_rumble andRightTrigger:(Uint16)right_rumbl
 
 -(void)cleanup
 {
-    [self->m_low_frequency_motor cleanup];
-    [self->m_high_frequency_motor cleanup];
+    [self.m_low_frequency_motor cleanup];
+    [self.m_high_frequency_motor cleanup];
 }
 
 @end