|
29 | 29 |
|
30 | 30 | #include "../../retroarch.h" |
31 | 31 | #include "../../driver.h" |
| 32 | +#include "../../configuration.h" |
32 | 33 |
|
33 | 34 | #include "../drivers_keyboard/keyboard_event_apple.h" |
34 | 35 | #include "../../ui/drivers/cocoa/cocoa_common.h" |
|
41 | 42 | #ifdef HAVE_MFI |
42 | 43 | #import <GameController/GameController.h> |
43 | 44 | #endif |
| 45 | +#if TARGET_OS_IOS |
| 46 | +#import <CoreHaptics/CoreHaptics.h> |
| 47 | +#endif |
44 | 48 |
|
45 | 49 | #if TARGET_OS_IPHONE |
46 | 50 | #define HIDKEY(X) X |
|
72 | 76 | static bool small_keyboard_active = false; |
73 | 77 | static icade_map_t icade_maps[MAX_ICADE_PROFILES][MAX_ICADE_KEYS]; |
74 | 78 | #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 */ |
75 | 83 | static UISelectionFeedbackGenerator *feedbackGenerator; |
76 | 84 | #endif |
77 | 85 | #endif |
@@ -379,9 +387,39 @@ void apple_input_keyboard_event(bool down, |
379 | 387 | #endif |
380 | 388 |
|
381 | 389 | #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 | + } |
385 | 423 | #endif |
386 | 424 |
|
387 | 425 | /* 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 |
861 | 899 | #if TARGET_OS_IOS |
862 | 900 | static void cocoa_input_keypress_vibrate(void) |
863 | 901 | { |
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 | + } |
866 | 966 | } |
867 | 967 | #endif |
868 | 968 |
|
|
0 commit comments