Skip to content

Instantly share code, notes, and snippets.

@HofiOne
Last active March 20, 2026 09:38
Show Gist options
  • Select an option

  • Save HofiOne/daf15897cf565e28315437728bce8b98 to your computer and use it in GitHub Desktop.

Select an option

Save HofiOne/daf15897cf565e28315437728bce8b98 to your computer and use it in GitHub Desktop.
Native iOS, tvOS vibration of the first available controller
#if TARGET_OS_IOS || TARGET_OS_TV
static CHHapticEngine* cachedHapticEngine = nil;
static GCController* cachedController = nil;
bool Native_VibrateController(float intensity, float duration)
{
// Clamp input
intensity = fmaxf(0.0f, fminf(intensity, 1.0f));
duration = fmaxf(0.02f, duration);
// Vibrate game controllers (iOS 14+ and tvOS 14+)
if (@available(iOS 14.0, tvOS 14.0,*)) {
NSArray<GCController*>* controllers = [GCController controllers];
// Use first available controller only
if (controllers.count == 0)
return NO;
GCController* controller = controllers[0];
if (controller.haptics) {
// Check if we need to recreate engine (controller changed or engine invalid)
if (cachedController != controller || cachedHapticEngine == nil) {
cachedController = nil;
// Clean up old engine
if (cachedHapticEngine) {
[cachedHapticEngine stopWithCompletionHandler:nil];
cachedHapticEngine = nil;
}
// Get first supported locality
NSSet<GCHapticsLocality>* localities = controller.haptics.supportedLocalities;
if (localities.count > 0) {
GCHapticsLocality locality = [localities anyObject];
// Create and cache new engine
cachedHapticEngine = [controller.haptics createEngineWithLocality:locality];
if (!cachedHapticEngine) {
NSLog(@"Error creating haptic engine");
return NO;
}
cachedController = controller;
NSError* error = nil;
[cachedHapticEngine startAndReturnError:&error];
if (error) {
NSLog(@"Error starting haptic engine: %@", error.localizedDescription);
cachedHapticEngine = nil;
cachedController = nil;
return NO;
}
}
}
// Use cached engine if available
if (cachedHapticEngine) {
NSError* error = nil;
// Create haptic event (this is relatively cheap)
CHHapticEvent* event = [[CHHapticEvent alloc] initWithEventType:CHHapticEventTypeHapticContinuous
parameters:@[
[[CHHapticEventParameter alloc] initWithParameterID:CHHapticEventParameterIDHapticIntensity value:intensity],
[[CHHapticEventParameter alloc] initWithParameterID:CHHapticEventParameterIDHapticSharpness value:0.5]
]
relativeTime:0
duration:duration];
CHHapticPattern* pattern = [[CHHapticPattern alloc] initWithEvents:@[event] parameters:@[] error:&error];
if (!error) {
id<CHHapticPatternPlayer> player = [cachedHapticEngine createPlayerWithPattern:pattern error:&error];
if (!error)
[player startAtTime:0 error:&error];
}
if (error)
NSLog(@"Error playing haptic pattern: %@", error.localizedDescription);
else
return YES;
}
}
}
return NO;
}
#endif
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment