Skip to content

Commit 943be33

Browse files
committed
apple: safer cleanup of haptic engines
1 parent 4979c66 commit 943be33

2 files changed

Lines changed: 90 additions & 13 deletions

File tree

input/drivers/cocoa_input.m

Lines changed: 39 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -742,6 +742,23 @@ static void cocoa_input_free(void *data)
742742
if (!apple || !data)
743743
return;
744744

745+
#if TARGET_OS_IOS
746+
if (@available(iOS 14, *))
747+
{
748+
if (keypressHapticEngine)
749+
{
750+
keypressHapticEngine.stoppedHandler = ^(CHHapticEngineStoppedReason reason) {};
751+
keypressHapticEngine.resetHandler = ^{};
752+
[keypressHapticEngine stopWithCompletionHandler:^(NSError *error) {
753+
keypressHapticPlayer = nil;
754+
keypressHapticEngine = nil;
755+
}];
756+
}
757+
}
758+
else if (@available(iOS 10, *))
759+
feedbackGenerator = nil;
760+
#endif
761+
745762
memset(apple_key_state, 0, sizeof(apple_key_state));
746763

747764
free(apple);
@@ -889,8 +906,8 @@ static void cocoa_input_init_haptic_engine(void) KEYPRESS_HAPTIC_AVAIL
889906
if (!error)
890907
{
891908
keypressHapticEngine.stoppedHandler = ^(CHHapticEngineStoppedReason reason) {
909+
/* Engine stopped (backgrounding/interruption) - clear player but keep engine */
892910
keypressHapticPlayer = nil;
893-
keypressHapticEngine = nil;
894911
};
895912
keypressHapticEngine.resetHandler = ^{
896913
if (keypressHapticEngine)
@@ -913,7 +930,18 @@ static void cocoa_input_keypress_vibrate(void)
913930
if (!settings || !keypressHapticEngine)
914931
return;
915932

933+
/* Ensure engine is started (may have been stopped by backgrounding) */
916934
NSError *error;
935+
[keypressHapticEngine startAndReturnError:&error];
936+
if (error)
937+
{
938+
/* Engine couldn't start - recreate it */
939+
keypressHapticEngine = nil;
940+
keypressHapticPlayer = nil;
941+
cocoa_input_init_haptic_engine();
942+
if (!keypressHapticEngine)
943+
return;
944+
}
917945
unsigned rumble_gain = settings->uints.input_rumble_gain;
918946
float intensity = (float)rumble_gain / 100.0f;
919947

@@ -950,14 +978,18 @@ static void cocoa_input_keypress_vibrate(void)
950978
else
951979
{
952980
/* Update intensity for existing player */
953-
CHHapticDynamicParameter *param = [[CHHapticDynamicParameter alloc]
954-
initWithParameterID:CHHapticDynamicParameterIDHapticIntensityControl
955-
value:intensity
956-
relativeTime:0];
957-
[keypressHapticPlayer sendParameters:[NSArray arrayWithObject:param] atTime:0 error:&error];
981+
if (keypressHapticPlayer)
982+
{
983+
CHHapticDynamicParameter *param = [[CHHapticDynamicParameter alloc]
984+
initWithParameterID:CHHapticDynamicParameterIDHapticIntensityControl
985+
value:intensity
986+
relativeTime:0];
987+
[keypressHapticPlayer sendParameters:[NSArray arrayWithObject:param] atTime:0 error:&error];
988+
}
958989
}
959990

960-
[keypressHapticPlayer startAtTime:0 error:&error];
991+
if (keypressHapticPlayer)
992+
[keypressHapticPlayer startAtTime:0 error:&error];
961993
}
962994
else
963995
{

input/drivers_joypad/mfi_joypad.m

Lines changed: 51 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -359,6 +359,15 @@ - (instancetype)initWithController:(GCController*)controller MFI_RUMBLE_AVAIL
359359
[self.engines addObject:engine];
360360

361361
__weak MFIRumbleController *weakSelf = self;
362+
engine.stoppedHandler = ^(CHHapticEngineStoppedReason reason) {
363+
MFIRumbleController *strongSelf = weakSelf;
364+
if (!strongSelf)
365+
return;
366+
367+
/* Engine stopped (backgrounding/interruption) - clear players but keep engine in set */
368+
strongSelf->_strongPlayer = nil;
369+
strongSelf->_weakPlayer = nil;
370+
};
362371
engine.resetHandler = ^{
363372
MFIRumbleController *strongSelf = weakSelf;
364373
if (!strongSelf)
@@ -416,12 +425,18 @@ - (void)shutdown
416425
{
417426
if (@available(iOS 14, tvOS 14, macOS 11, *))
418427
{
428+
if (_weakPlayer) [_weakPlayer cancelAndReturnError:nil];
429+
if (_strongPlayer) [_strongPlayer cancelAndReturnError:nil];
430+
419431
for (CHHapticEngine *eng in self.engines)
432+
{
433+
eng.stoppedHandler = ^(CHHapticEngineStoppedReason reason) {};
420434
eng.resetHandler = ^{};
435+
[eng stopWithCompletionHandler:nil];
436+
}
421437
[self.engines removeAllObjects];
422-
if (_weakPlayer) [_weakPlayer cancelAndReturnError:nil];
423-
_weakPlayer = nil;
424-
if (_strongPlayer) [_strongPlayer cancelAndReturnError:nil];
438+
439+
_weakPlayer = nil;
425440
_strongPlayer = nil;
426441
}
427442
}
@@ -553,9 +568,9 @@ static void apple_gamecontroller_device_haptics_setup(void) IPHONE_RUMBLE_AVAIL
553568

554569
deviceHapticEngine.stoppedHandler = ^(CHHapticEngineStoppedReason reason)
555570
{
571+
/* Engine stopped (backgrounding/interruption) - clear players but keep engine */
556572
deviceWeakPlayer = nil;
557573
deviceStrongPlayer = nil;
558-
deviceHapticEngine = nil;
559574
};
560575
deviceHapticEngine.resetHandler = ^{
561576
if (!deviceHapticEngine)
@@ -573,10 +588,23 @@ static void apple_gamecontroller_device_haptics_setup(void) IPHONE_RUMBLE_AVAIL
573588
if (!deviceHapticEngine)
574589
return nil;
575590

591+
/* Ensure engine is started (may have been stopped by backgrounding) */
592+
NSError *error;
593+
[deviceHapticEngine startAndReturnError:&error];
594+
if (error)
595+
{
596+
/* Engine couldn't start - recreate it */
597+
deviceHapticEngine = nil;
598+
deviceWeakPlayer = nil;
599+
deviceStrongPlayer = nil;
600+
apple_gamecontroller_device_haptics_setup();
601+
if (!deviceHapticEngine)
602+
return nil;
603+
}
604+
576605
CHHapticEventParameter *intense;
577606
CHHapticEvent *event;
578607
CHHapticPattern *pattern;
579-
NSError *error;
580608

581609
CHHapticEventParameter *sharp;
582610

@@ -654,7 +682,24 @@ static void apple_gamecontroller_device_haptics_setup(void) IPHONE_RUMBLE_AVAIL
654682
return (void*)-1;
655683
}
656684

657-
static void apple_gamecontroller_joypad_destroy(void) { }
685+
static void apple_gamecontroller_joypad_destroy(void)
686+
{
687+
#if TARGET_OS_IOS
688+
if (@available(iOS 14, *))
689+
{
690+
if (deviceHapticEngine)
691+
{
692+
deviceHapticEngine.stoppedHandler = ^(CHHapticEngineStoppedReason reason) {};
693+
deviceHapticEngine.resetHandler = ^{};
694+
[deviceHapticEngine stopWithCompletionHandler:^(NSError *error) {
695+
deviceWeakPlayer = nil;
696+
deviceStrongPlayer = nil;
697+
deviceHapticEngine = nil;
698+
}];
699+
}
700+
}
701+
#endif
702+
}
658703

659704
static int32_t apple_gamecontroller_joypad_button(
660705
unsigned port, uint16_t joykey)

0 commit comments

Comments
 (0)