Skip to content

Commit 357fce8

Browse files
committed
iOS: stronger haptics, obey strength setting
fixes #15625
1 parent 683899e commit 357fce8

File tree

2 files changed

+119
-11
lines changed

2 files changed

+119
-11
lines changed

input/drivers/cocoa_input.m

Lines changed: 105 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929

3030
#include "../../retroarch.h"
3131
#include "../../driver.h"
32+
#include "../../configuration.h"
3233

3334
#include "../drivers_keyboard/keyboard_event_apple.h"
3435
#include "../../ui/drivers/cocoa/cocoa_common.h"
@@ -41,6 +42,9 @@
4142
#ifdef HAVE_MFI
4243
#import <GameController/GameController.h>
4344
#endif
45+
#if TARGET_OS_IOS
46+
#import <CoreHaptics/CoreHaptics.h>
47+
#endif
4448

4549
#if TARGET_OS_IPHONE
4650
#define HIDKEY(X) X
@@ -72,6 +76,10 @@
7276
static bool small_keyboard_active = false;
7377
static icade_map_t icade_maps[MAX_ICADE_PROFILES][MAX_ICADE_KEYS];
7478
#if TARGET_OS_IOS
79+
#define KEYPRESS_HAPTIC_AVAIL API_AVAILABLE(ios(14.0))
80+
static CHHapticEngine *keypressHapticEngine KEYPRESS_HAPTIC_AVAIL;
81+
static id<CHHapticPatternPlayer> keypressHapticPlayer KEYPRESS_HAPTIC_AVAIL;
82+
/* Fallback for iOS 10-13 */
7583
static UISelectionFeedbackGenerator *feedbackGenerator;
7684
#endif
7785
#endif
@@ -379,9 +387,39 @@ void apple_input_keyboard_event(bool down,
379387
#endif
380388

381389
#if TARGET_OS_IOS
382-
if (!feedbackGenerator)
383-
feedbackGenerator = [[UISelectionFeedbackGenerator alloc] init];
384-
[feedbackGenerator prepare];
390+
if (@available(iOS 14, *))
391+
{
392+
if (!keypressHapticEngine && CHHapticEngine.capabilitiesForHardware.supportsHaptics)
393+
{
394+
NSError *error;
395+
keypressHapticEngine = [[CHHapticEngine alloc] initAndReturnError:&error];
396+
if (!error)
397+
{
398+
[keypressHapticEngine startAndReturnError:&error];
399+
if (!error)
400+
{
401+
keypressHapticEngine.stoppedHandler = ^(CHHapticEngineStoppedReason reason) {
402+
keypressHapticPlayer = nil;
403+
keypressHapticEngine = nil;
404+
};
405+
keypressHapticEngine.resetHandler = ^{
406+
if (keypressHapticEngine)
407+
[keypressHapticEngine startAndReturnError:nil];
408+
};
409+
}
410+
}
411+
}
412+
}
413+
else
414+
{
415+
/* Fallback for iOS 10-13 */
416+
if (@available(iOS 10, *))
417+
{
418+
if (!feedbackGenerator)
419+
feedbackGenerator = [[UISelectionFeedbackGenerator alloc] init];
420+
[feedbackGenerator prepare];
421+
}
422+
}
385423
#endif
386424

387425
/* TODO/FIXME - shouldn't we free the above in case this fails for
@@ -861,8 +899,70 @@ static float cocoa_input_get_sensor_input(void *data, unsigned port, unsigned id
861899
#if TARGET_OS_IOS
862900
static void cocoa_input_keypress_vibrate(void)
863901
{
864-
[feedbackGenerator selectionChanged];
865-
[feedbackGenerator prepare];
902+
if (@available(iOS 14, *))
903+
{
904+
settings_t *settings = config_get_ptr();
905+
if (!settings || !keypressHapticEngine)
906+
return;
907+
908+
NSError *error;
909+
unsigned rumble_gain = settings->uints.input_rumble_gain;
910+
float intensity = (float)rumble_gain / 100.0f;
911+
912+
/* Create player on first use */
913+
if (!keypressHapticPlayer)
914+
{
915+
CHHapticEventParameter *intense;
916+
CHHapticEventParameter *sharp;
917+
CHHapticEvent *event;
918+
CHHapticPattern *pattern;
919+
920+
intense = [[CHHapticEventParameter alloc]
921+
initWithParameterID:CHHapticEventParameterIDHapticIntensity
922+
value:intensity];
923+
sharp = [[CHHapticEventParameter alloc]
924+
initWithParameterID:CHHapticEventParameterIDHapticSharpness
925+
value:1.0];
926+
event = [[CHHapticEvent alloc]
927+
initWithEventType:CHHapticEventTypeHapticTransient
928+
parameters:[NSArray arrayWithObjects:intense, sharp, nil]
929+
relativeTime:0];
930+
pattern = [[CHHapticPattern alloc]
931+
initWithEvents:[NSArray arrayWithObject:event]
932+
parameters:[[NSArray alloc] init]
933+
error:&error];
934+
935+
if (error)
936+
return;
937+
938+
keypressHapticPlayer = [keypressHapticEngine createPlayerWithPattern:pattern error:&error];
939+
if (error)
940+
return;
941+
}
942+
else
943+
{
944+
/* Update intensity for existing player */
945+
CHHapticDynamicParameter *param = [[CHHapticDynamicParameter alloc]
946+
initWithParameterID:CHHapticDynamicParameterIDHapticIntensityControl
947+
value:intensity
948+
relativeTime:0];
949+
[keypressHapticPlayer sendParameters:[NSArray arrayWithObject:param] atTime:0 error:&error];
950+
}
951+
952+
[keypressHapticPlayer startAtTime:0 error:&error];
953+
}
954+
else
955+
{
956+
/* Fallback for iOS 10-13 */
957+
if (@available(iOS 10, *))
958+
{
959+
if (feedbackGenerator)
960+
{
961+
[feedbackGenerator selectionChanged];
962+
[feedbackGenerator prepare];
963+
}
964+
}
965+
}
866966
}
867967
#endif
868968

input/drivers_joypad/mfi_joypad.m

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@
5050
static int16_t mfi_axes[MAX_USERS][MAX_MFI_AXES];
5151
static uint32_t mfi_controllers[MAX_MFI_CONTROLLERS];
5252
static MFIRumbleController *mfi_rumblers[MAX_MFI_CONTROLLERS];
53-
#define MFI_WEAK_RUMBLE 0.3f
53+
#define MFI_WEAK_RUMBLE 0.5f
5454
static NSMutableArray *mfiControllers;
5555
static bool mfi_inited;
5656

@@ -372,12 +372,17 @@ - (instancetype)initWithController:(GCController*)controller MFI_RUMBLE_AVAIL
372372
CHHapticEvent *event;
373373
CHHapticPattern *pattern;
374374

375+
CHHapticEventParameter *sharp;
376+
375377
intense = [[CHHapticEventParameter alloc]
376378
initWithParameterID:CHHapticEventParameterIDHapticIntensity
377379
value:intensity];
380+
sharp = [[CHHapticEventParameter alloc]
381+
initWithParameterID:CHHapticEventParameterIDHapticSharpness
382+
value:1.0];
378383
event = [[CHHapticEvent alloc]
379384
initWithEventType:CHHapticEventTypeHapticContinuous
380-
parameters:[NSArray arrayWithObjects:intense, nil]
385+
parameters:[NSArray arrayWithObjects:intense, sharp, nil]
381386
relativeTime:0
382387
duration:GCHapticDurationInfinite];
383388
pattern = [[CHHapticPattern alloc]
@@ -573,12 +578,17 @@ static void apple_gamecontroller_device_haptics_setup(void) IPHONE_RUMBLE_AVAIL
573578
CHHapticPattern *pattern;
574579
NSError *error;
575580

581+
CHHapticEventParameter *sharp;
582+
576583
intense = [[CHHapticEventParameter alloc]
577584
initWithParameterID:CHHapticEventParameterIDHapticIntensity
578585
value:intensity];
586+
sharp = [[CHHapticEventParameter alloc]
587+
initWithParameterID:CHHapticEventParameterIDHapticSharpness
588+
value:1.0];
579589
event = [[CHHapticEvent alloc]
580590
initWithEventType:CHHapticEventTypeHapticContinuous
581-
parameters:[NSArray arrayWithObjects:intense, nil]
591+
parameters:[NSArray arrayWithObjects:intense, sharp, nil]
582592
relativeTime:0
583593
duration:GCHapticDurationInfinite];
584594
pattern = [[CHHapticPattern alloc]
@@ -606,7 +616,7 @@ static void apple_gamecontroller_device_haptics_setup(void) IPHONE_RUMBLE_AVAIL
606616
static id<CHHapticPatternPlayer> apple_gamecontroller_device_haptics_weak_player(void) IPHONE_RUMBLE_AVAIL
607617
{
608618
if (!deviceWeakPlayer)
609-
deviceWeakPlayer = apple_gamecontroller_device_haptics_create_player(0.5f);
619+
deviceWeakPlayer = apple_gamecontroller_device_haptics_create_player(0.7f);
610620
return deviceWeakPlayer;
611621
}
612622
#endif
@@ -770,8 +780,6 @@ static bool apple_gamecontroller_joypad_set_rumble(unsigned pad,
770780
{
771781
CHHapticDynamicParameter *param = NULL;
772782
float str = (float)strength / 65535.0f;
773-
if (type == RETRO_RUMBLE_WEAK)
774-
str *= MFI_WEAK_RUMBLE;
775783
param = [[CHHapticDynamicParameter alloc]
776784
initWithParameterID:CHHapticDynamicParameterIDHapticIntensityControl
777785
value:str

0 commit comments

Comments
 (0)