CoreHaptics support for rumble and button feedback

This commit is contained in:
Lior Halphon 2023-01-14 18:28:08 +02:00
parent 3e75016fe0
commit e0af961ad3
6 changed files with 111 additions and 4 deletions

View File

@ -55,7 +55,7 @@ static OSStatus render(
// Set our tone rendering function on the unit
AURenderCallbackStruct input;
input.inputProc = (void*)render;
input.inputProcRefCon = (__bridge void * _Nullable)(self);
input.inputProcRefCon = (__bridge void *)(self);
err = AudioUnitSetProperty(audioUnit,
kAudioUnitProperty_SetRenderCallback,
kAudioUnitScope_Input,

View File

@ -186,7 +186,7 @@ endif
CFLAGS += -arch arm64 -miphoneos-version-min=11.0 -isysroot $(SYSROOT) -IAppleCommon
LDFLAGS += -arch arm64
OCFLAGS += -x objective-c -fobjc-arc -Wno-deprecated-declarations -isysroot $(SYSROOT)
LDFLAGS += -lobjc -framework UIKit -framework Foundation -framework CoreGraphics -framework Metal -framework MetalKit -framework AudioToolbox -framework AVFoundation -miphoneos-version-min=11.0 -isysroot $(SYSROOT)
LDFLAGS += -lobjc -framework UIKit -framework Foundation -framework CoreGraphics -framework Metal -framework MetalKit -framework AudioToolbox -framework AVFoundation -weak_framework CoreHaptics -miphoneos-version-min=11.0 -isysroot $(SYSROOT)
CODESIGN := codesign -fs -
else
ifeq ($(PLATFORM),Darwin)

View File

@ -1,5 +1,6 @@
#import "GBBackgroundView.h"
#import "GBViewMetal.h"
#import "GBHapticManager.h"
double CGPointSquaredDistance(CGPoint a, CGPoint b)
{
@ -35,6 +36,7 @@ static void positionView(UIImageView *view, CGPoint position)
UIImageView *_bButtonView;
UIImageView *_startButtonView;
UIImageView *_selectButtonView;
GB_key_mask_t _lastMask;
}
- (instancetype)init
@ -130,6 +132,10 @@ static void positionView(UIImageView *view, CGPoint position)
}
}
GB_set_key_mask(_gbView.gb, mask);
if (mask & ~_lastMask) {
[[GBHapticManager sharedManager] doTapHaptic];
}
_lastMask = mask;
}
- (BOOL)isMultipleTouchEnabled

7
iOS/GBHapticManager.h Normal file
View File

@ -0,0 +1,7 @@
#import <Foundation/Foundation.h>
@interface GBHapticManager : NSObject
+ (instancetype)sharedManager;
- (void)doTapHaptic;
- (void)setRumbleStrength:(double)rumble;
@end

93
iOS/GBHapticManager.m Normal file
View File

@ -0,0 +1,93 @@
#import "GBHapticManager.h"
#import <CoreHaptics/CoreHaptics.h>
@implementation GBHapticManager
{
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wpartial-availability"
CHHapticEngine *_engine;
id<CHHapticPatternPlayer> _rumblePlayer;
#pragma clang diagnostic pop
double _rumble;
}
+ (instancetype)sharedManager
{
static dispatch_once_t onceToken;
static GBHapticManager *manager;
dispatch_once(&onceToken, ^{
manager = [[self alloc] init];
});
return manager;
}
- (instancetype)init
{
self = [super init];
if (!self) return nil;
if (@available(iOS 13.0, *)) {
_engine = [[CHHapticEngine alloc] initAndReturnError:nil];
_engine.playsHapticsOnly = true;
_engine.autoShutdownEnabled = true;
}
else {
return nil;
}
if (!_engine) return nil;
return self;
}
#pragma clang diagnostic ignored "-Wpartial-availability"
- (CHHapticEvent *) eventWithType:(CHHapticEventType)type
sharpness:(double)sharpness
intensity:(double)intensity
duration:(NSTimeInterval)duration
{
return [[CHHapticEvent alloc] initWithEventType:CHHapticEventTypeHapticTransient
parameters:@[[[CHHapticEventParameter alloc] initWithParameterID:CHHapticEventParameterIDHapticSharpness
value:sharpness],
[[CHHapticEventParameter alloc] initWithParameterID:CHHapticEventParameterIDHapticIntensity
value:intensity]]
relativeTime:CHHapticTimeImmediate
duration:duration];
}
- (void)doTapHaptic
{
if (_rumble) return;
CHHapticPattern *pattern = [[CHHapticPattern alloc] initWithEvents:@[[self eventWithType:CHHapticEventTypeHapticTransient
sharpness:0.25
intensity:0.75
duration:1.0]]
parameters:nil
error:nil];
id<CHHapticPatternPlayer> player = [_engine createPlayerWithPattern:pattern error:nil];
[player startAtTime:0 error:nil];
}
- (void)setRumbleStrength:(double)rumble
{
if (rumble == 0) {
[_rumblePlayer stopAtTime:0 error:nil];
_rumblePlayer = nil;
_rumble = 0;
return;
}
_rumble = rumble;
CHHapticPattern *pattern = [[CHHapticPattern alloc] initWithEvents:@[[self eventWithType:CHHapticEventTypeHapticContinuous
sharpness:0.75
intensity:rumble
duration:1.0]]
parameters:nil
error:nil];
id<CHHapticPatternPlayer> newPlayer = [_engine createPlayerWithPattern:pattern error:nil];
[newPlayer startAtTime:0 error:nil];
[_rumblePlayer stopAtTime:0 error:nil];
_rumblePlayer = newPlayer;
}
@end

View File

@ -6,6 +6,7 @@
#import "GBROMManager.h"
#import "GBLoadROMTableViewController.h"
#import "GBBackgroundView.h"
#import "GBHapticManager.h"
#include <Core/gb.h>
@implementation GBViewController
@ -116,7 +117,7 @@ static void rumbleCallback(GB_gameboy_t *gb, double amp)
[[NSNotificationCenter defaultCenter] addObserverForName:@"GBROMChanged"
object:nil
queue:nil
usingBlock:^(NSNotification * _Nonnull note) {
usingBlock:^(NSNotification *note) {
[self loadROM];
[self start];
}];
@ -305,7 +306,7 @@ static void rumbleCallback(GB_gameboy_t *gb, double amp)
- (void)rumbleChanged:(double)amp
{
// TODO
[[GBHapticManager sharedManager] setRumbleStrength:amp];
}
- (void)updateRumbleMode