Refactored code and removed notification replacing them for async calls

This commit is contained in:
Andrea Alberti 2025-09-30 12:08:05 +02:00
parent 468d29c42d
commit f387e67a8a
2 changed files with 227 additions and 231 deletions

View File

@ -76,6 +76,8 @@
@property (nonatomic, strong) NSStatusItem *statusBar;
@property (atomic, assign) BOOL isSendingAppleEvent;
@property (assign, nonatomic) NSInteger volumeInc;
@property (assign, nonatomic) bool AppleRemoteConnected;
@property (assign, nonatomic) bool StartAtLogin;
@ -104,19 +106,7 @@
- (BOOL)tryCreateEventTap;
// - (void)appleRemoteButton: (AppleRemoteEventIdentifier)buttonIdentifier pressedDown: (BOOL) pressedDown clickCount: (unsigned int) count;
- (void)resetEventTap;
- (void)stopVolumeRampTimer;
- (void)updatePercentages;
- (void)wasAuthorized;
- (bool)createEventTap;
- (void)handleEventTapDisabledByUser;
- (void)handleAsynchronouslyTappedEventWithKeyCode:(int)keyCode
keyState:(BOOL)keyState
keyIsRepeat:(BOOL)keyIsRepeat

View File

@ -31,14 +31,18 @@ void handleSIGTERM(int sig) {
#pragma mark - Tapping key stroke events
//static void displayPreferencesChanged(CGDirectDisplayID displayID, CGDisplayChangeSummaryFlags flags, void *userInfo) {
// [[NSNotificationCenter defaultCenter] postNotificationName:@"displayResolutionHasChanged" object:NULL];
//}
CGEventRef event_tap_callback(CGEventTapProxy proxy, CGEventType type, CGEventRef event, void *refcon)
{
if (type == kCGEventTapDisabledByTimeout) {
NSLog(@"[Volume Control] Event tap disabled due to timeout. Disabling tapping.");
AppDelegate *app = (__bridge AppDelegate *)refcon;
if (app.isSendingAppleEvent) {
// False positive timeout caused by TCC
NSLog(@"[Volume Control] Tap disabled during AppleEvent/TCC dialog → restarting tap.");
dispatch_async(dispatch_get_main_queue(), ^{
[app setTapping:YES]; // try to resume
});
} else {
// Real unresponsiveness
dispatch_async(dispatch_get_main_queue(), ^{
AppDelegate *app = (__bridge AppDelegate *)refcon;
[app setTapping:NO];
@ -59,6 +63,7 @@ CGEventRef event_tap_callback(CGEventTapProxy proxy, CGEventType type, CGEventRe
});
return event; // always return quickly
}
}
// Pass through events we don't care about
if (type != NX_SYSDEFINED) return event;
@ -122,6 +127,18 @@ CGEventRef event_tap_callback(CGEventTapProxy proxy, CGEventType type, CGEventRe
BOOL _muteDown;
}
// Forward declare private methods
- (id)runningPlayer;
- (void)completeInitialization;
- (void)setVolumeUp:(bool)increase;
- (void) setItunesVolume:(NSInteger)volume;
- (void) setSpotifyVolume:(NSInteger)volume;
- (void) setSystemVolume:(NSInteger)volume;
- (void)stopVolumeRampTimer;
- (void)updatePercentages;
- (bool)createEventTap;
- (void)handleEventTapDisabledByUser;
@end
#pragma mark - Extention music applications
@ -139,8 +156,13 @@ CGEventRef event_tap_callback(CGEventTapProxy proxy, CGEventType type, CGEventRe
- (double) currentVolume
{
AppDelegate *app = (AppDelegate *)NSApp.delegate;
app.isSendingAppleEvent = YES;
double vol = [musicPlayer soundVolume];
app.isSendingAppleEvent = NO;
if (fabs(vol-[self doubleVolume])<1)
{
vol = [self doubleVolume];
@ -241,7 +263,6 @@ static NSTimeInterval updateSystemVolumeInterval=0.1f;
eventTap = nil;
}
[[NSNotificationCenter defaultCenter] removeObserver:self];
[[[NSWorkspace sharedWorkspace] notificationCenter] removeObserver:self];
systemAudio = nil;
@ -268,6 +289,11 @@ static NSTimeInterval updateSystemVolumeInterval=0.1f;
preferences = nil;
// IMPORTANT: Use [NSApp terminate:nil] for a clean exit.
// This ensures AppKit tears down the NSStatusItem properly
// and preserves the status bar icon position between launches.
// Simply returning or calling exit() would skip this cleanup
// and cause the icon to reset to the default position.
[NSApp terminate:nil];
}
@ -322,12 +348,12 @@ static NSTimeInterval updateSystemVolumeInterval=0.1f;
}
} else {
// Legacy fallback (macOS 12 and older)
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
if (!SMLoginItemSetEnabled((__bridge CFStringRef)helperBundleID, enabled)) {
NSLog(@"[Volume Control] SMLoginItemSetEnabled failed.");
}
#pragma clang diagnostic pop
#pragma clang diagnostic pop
}
if (savePreferences) {
@ -373,7 +399,7 @@ static NSTimeInterval updateSystemVolumeInterval=0.1f;
{
[volumeRampTimer invalidate];
volumeRampTimer=nil;
[[NSNotificationCenter defaultCenter] postNotificationName:@"SoundFeedback" object:NULL];
[self emitAcousticFeedback];
checkPlayerTimer = [NSTimer timerWithTimeInterval:checkPlayerTimeout target:self selector:@selector(resetCurrentPlayer:) userInfo:nil repeats:NO];
[[NSRunLoop mainRunLoop] addTimer:checkPlayerTimer forMode:NSRunLoopCommonModes];
@ -512,8 +538,7 @@ static NSTimeInterval updateSystemVolumeInterval=0.1f;
if (keyState == 1) {
_muteDown = true;
[[NSNotificationCenter defaultCenter] postNotificationName:@"MuteVol" object:nil];
// [self MuteVol:nil];
[self MuteVol];
} else {
_muteDown = false;
}
@ -529,11 +554,8 @@ static NSTimeInterval updateSystemVolumeInterval=0.1f;
if (keyState == 1) {
if (!self->volumeRampTimer) {
if (keyCode == NX_KEYTYPE_SOUND_UP) {
[[NSNotificationCenter defaultCenter] postNotificationName:(keyIsRepeat ? @"IncVolRamp" : @"IncVol") object:nil];
} else {
[[NSNotificationCenter defaultCenter] postNotificationName:(keyIsRepeat ? @"DecVolRamp" : @"DecVol") object:nil];
}
BOOL increase = (keyCode == NX_KEYTYPE_SOUND_UP);
[self adjustVolumeUp:increase ramp:keyIsRepeat];
}
} else {
if (self->volumeRampTimer) {
@ -559,22 +581,24 @@ static NSTimeInterval updateSystemVolumeInterval=0.1f;
// NSLog(@"%d keycode (up) sent",key);
}
- (void)PlayPauseMusic:(NSNotification *)aNotification
/*
- (void)PlayPauseMusic
{
[self sendMediaKey:NX_KEYTYPE_PLAY];
}
- (void)NextTrackMusic:(NSNotification *)aNotification
- (void)NextTrackMusic
{
[self sendMediaKey:NX_KEYTYPE_NEXT];
}
- (void)PreviousTrackMusic:(NSNotification *)aNotification
- (void)PreviousTrackMusic
{
[self sendMediaKey:NX_KEYTYPE_PREVIOUS];
}
*/
- (void)MuteVol:(NSNotification *)aNotification
- (void)MuteVol
{
id runningPlayerPtr = [self runningPlayer];
@ -594,10 +618,12 @@ static NSTimeInterval updateSystemVolumeInterval=0.1f;
if (@available(macOS 16.0, *)) {
// Running on Tahoe (2026) or newer
} else {
[[self->OSDManager sharedManager] showImage:OSDGraphicSpeakerMute onDisplayID:CGSMainDisplayID() priority:OSDPriorityDefault msecUntilFade:1000 filledChiclets:0 totalChiclets:(unsigned int)100 locked:NO];
id osdMgr = [self->OSDManager sharedManager];
if (osdMgr) {
[osdMgr showImage:OSDGraphicSpeakerMute onDisplayID:CGSMainDisplayID() priority:OSDPriorityDefault msecUntilFade:1000 filledChiclets:0 totalChiclets:(unsigned int)100 locked:NO];
}
}
}
}
else
{
@ -612,7 +638,10 @@ static NSTimeInterval updateSystemVolumeInterval=0.1f;
if (@available(macOS 16.0, *)) {
// Running on Tahoe (2026) or newer
} else {
[[self->OSDManager sharedManager] showImage:OSDGraphicSpeaker onDisplayID:CGSMainDisplayID() priority:OSDPriorityDefault msecUntilFade:1000 filledChiclets:(unsigned int)[runningPlayerPtr oldVolume] totalChiclets:(unsigned int)100 locked:NO];
id osdMgr = [self->OSDManager sharedManager];
if (osdMgr) {
[osdMgr showImage:OSDGraphicSpeaker onDisplayID:CGSMainDisplayID() priority:OSDPriorityDefault msecUntilFade:1000 filledChiclets:(unsigned int)[runningPlayerPtr oldVolume] totalChiclets:(unsigned int)100 locked:NO];
}
}
}
@ -634,37 +663,25 @@ static NSTimeInterval updateSystemVolumeInterval=0.1f;
}
}
- (void)IncVol:(NSNotification *)aNotification
{
if( [[aNotification name] isEqualToString:@"IncVolRamp"] )
{
- (void)adjustVolumeUp:(BOOL)increase ramp:(BOOL)ramp {
if (ramp) {
[checkPlayerTimer invalidate];
checkPlayerTimer = nil;
volumeRampTimer=[NSTimer timerWithTimeInterval:volumeRampTimeInterval*(NSTimeInterval)increment target:self selector:@selector(rampVolumeUp:) userInfo:nil repeats:YES];
SEL selector = increase ? @selector(rampVolumeUp:) : @selector(rampVolumeDown:);
volumeRampTimer = [NSTimer timerWithTimeInterval:volumeRampTimeInterval * (NSTimeInterval)increment
target:self
selector:selector
userInfo:nil
repeats:YES];
[[NSRunLoop mainRunLoop] addTimer:volumeRampTimer forMode:NSRunLoopCommonModes];
if(timerImgSpeaker) {[timerImgSpeaker invalidate]; timerImgSpeaker=nil;}
if (timerImgSpeaker) {
[timerImgSpeaker invalidate];
timerImgSpeaker = nil;
}
else
{
[self setVolumeUp:true];
}
}
- (void)DecVol:(NSNotification *)aNotification
{
if( [[aNotification name] isEqualToString:@"DecVolRamp"] )
{
[checkPlayerTimer invalidate];
checkPlayerTimer = nil;
volumeRampTimer=[NSTimer timerWithTimeInterval:volumeRampTimeInterval*(NSTimeInterval)increment target:self selector:@selector(rampVolumeDown:) userInfo:nil repeats:YES];
[[NSRunLoop mainRunLoop] addTimer:volumeRampTimer forMode:NSRunLoopCommonModes];
if(timerImgSpeaker) {[timerImgSpeaker invalidate]; timerImgSpeaker=nil;}
}
else
{
[self setVolumeUp:false];
} else {
[self setVolumeUp:increase];
}
}
@ -758,7 +775,7 @@ static NSTimeInterval updateSystemVolumeInterval=0.1f;
return YES; // Default behavior
}
- (void)emitAcousticFeedback:(NSNotification *)aNotification
- (void)emitAcousticFeedback
{
if([self PlaySoundFeedback] && (_AppleCMDModifierPressed != _UseAppleCMDModifier || [[self runningPlayer] isKindOfClass:[SystemApplication class]]))
{
@ -770,17 +787,6 @@ static NSTimeInterval updateSystemVolumeInterval=0.1f;
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
// NSLog(@"FINISHED LAUNCHING");
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(emitAcousticFeedback:) name:@"SoundFeedback" object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(IncVol:) name:@"IncVol" object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(IncVol:) name:@"IncVolRamp" object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(DecVol:) name:@"DecVol" object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(DecVol:) name:@"DecVolRamp" object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(MuteVol:) name:@"MuteVol" object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(PlayPauseMusic:) name:@"PlayPauseMusic" object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(NextTrackMusic:) name:@"NextTrackMusic" object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(PreviousTrackMusic:) name:@"PreviousTrackMusic" object:nil];
[[[NSWorkspace sharedWorkspace] notificationCenter] addObserver: self selector: @selector(receiveWakeNote:) name:NSWorkspaceDidWakeNotification object: NULL];
signal(SIGTERM, handleSIGTERM);
@ -1083,11 +1089,6 @@ static NSTimeInterval updateSystemVolumeInterval=0.1f;
[self setTapping:[self Tapping]];
}
- (void) dealloc
{
}
- (void)resetCurrentPlayer:(NSTimer*)theTimer
{
// Keep memory of the current player until this timeout is reached
@ -1153,9 +1154,9 @@ static NSTimeInterval updateSystemVolumeInterval=0.1f;
if (volume<0) volume=0;
if (volume>100) volume=100;
OSDGraphic image;
NSInteger numFullBlks;
NSInteger numQrtsBlks;
OSDGraphic image = 0;
NSInteger numFullBlks = 0;
NSInteger numQrtsBlks = 0;
if (@available(macOS 16.0, *)) {
// Running on Tahoe (2026) or newer
@ -1172,7 +1173,12 @@ static NSTimeInterval updateSystemVolumeInterval=0.1f;
if (@available(macOS 16.0, *)) {
// Running on Tahoe (2026) or newer
} else {
[[self->OSDManager sharedManager] showImage:image onDisplayID:CGSMainDisplayID() priority:OSDPriorityDefault msecUntilFade:1000 filledChiclets:(unsigned int)(round(((numFullBlks*4+numQrtsBlks)*1.5625)*100)) totalChiclets:(unsigned int)10000 locked:NO];
if(image) {
id osdMgr = [self->OSDManager sharedManager];
if (osdMgr) {
[osdMgr showImage:image onDisplayID:CGSMainDisplayID() priority:OSDPriorityDefault msecUntilFade:1000 filledChiclets:(unsigned int)(round(((numFullBlks*4+numQrtsBlks)*1.5625)*100)) totalChiclets:(unsigned int)10000 locked:NO];
}
}
}
}
@ -1182,7 +1188,7 @@ static NSTimeInterval updateSystemVolumeInterval=0.1f;
}
if(self->volumeRampTimer == nil)
[self emitAcousticFeedback:nil];
[self emitAcousticFeedback];
if( runningPlayerPtr == iTunes)
[self setItunesVolume:volume];