diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..5ca0973 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +.DS_Store + diff --git a/Example/HIDRemoteExample.xcodeproj/project.pbxproj b/Example/HIDRemoteExample.xcodeproj/project.pbxproj index 934dc6a..7bdef5f 100644 --- a/Example/HIDRemoteExample.xcodeproj/project.pbxproj +++ b/Example/HIDRemoteExample.xcodeproj/project.pbxproj @@ -18,8 +18,8 @@ DC74BB2C107E2D7600616791 /* remoteButtonSelect.png in Resources */ = {isa = PBXBuildFile; fileRef = DC74BB25107E2D7600616791 /* remoteButtonSelect.png */; }; DC74BB2D107E2D7600616791 /* remoteButtonUp.png in Resources */ = {isa = PBXBuildFile; fileRef = DC74BB26107E2D7600616791 /* remoteButtonUp.png */; }; DC74BB2E107E2D7600616791 /* remoteButtonRight.png in Resources */ = {isa = PBXBuildFile; fileRef = DC74BB27107E2D7600616791 /* remoteButtonRight.png */; }; - DC77207B10876E1A00FC8000 /* DemoController.m in Sources */ = {isa = PBXBuildFile; fileRef = DC77207810876E1A00FC8000 /* DemoController.m */; }; - DC77207C10876E1A00FC8000 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = DC77207A10876E1A00FC8000 /* main.m */; }; + DC77207B10876E1A00FC8000 /* DemoController.m in Sources */ = {isa = PBXBuildFile; fileRef = DC77207810876E1A00FC8000 /* DemoController.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; + DC77207C10876E1A00FC8000 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = DC77207A10876E1A00FC8000 /* main.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; }; DC7B03411A94B10900A0F571 /* Carbon.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DCDC22EE1080AB18001813E3 /* Carbon.framework */; }; DCDC1AC9107E3066001813E3 /* HIDRemote.m in Sources */ = {isa = PBXBuildFile; fileRef = DCDC1AC8107E3066001813E3 /* HIDRemote.m */; }; DCDC1ACE107E3075001813E3 /* IOKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DCDC1ACD107E3075001813E3 /* IOKit.framework */; }; @@ -279,6 +279,9 @@ isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ENABLE_OBJC_ARC = NO; + "CLANG_ENABLE_OBJC_ARC[arch=i386]" = NO; + "CLANG_ENABLE_OBJC_ARC[arch=x86_64]" = YES; COPY_PHASE_STRIP = NO; GCC_DYNAMIC_NO_PIC = NO; GCC_ENABLE_FIX_AND_CONTINUE = YES; @@ -289,6 +292,7 @@ GCC_VERSION = ""; INFOPLIST_FILE = "HIDRemoteExample-Info.plist"; INSTALL_PATH = "$(HOME)/Applications"; + MACOSX_DEPLOYMENT_TARGET = 10.6; PRODUCT_NAME = "HID Remote Example"; }; name = Debug; @@ -297,12 +301,15 @@ isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; + "CLANG_ENABLE_OBJC_ARC[arch=i386]" = NO; + "CLANG_ENABLE_OBJC_ARC[arch=x86_64]" = YES; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; GCC_MODEL_TUNING = G5; GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PREFIX_HEADER = HIDRemoteExample_Prefix.pch; INFOPLIST_FILE = "HIDRemoteExample-Info.plist"; INSTALL_PATH = "$(HOME)/Applications"; + MACOSX_DEPLOYMENT_TARGET = 10.6; PRODUCT_NAME = "HID Remote Example"; }; name = Release; diff --git a/Example/HIDRemoteExample.xcodeproj/project.xcworkspace/xcuserdata/felix.xcuserdatad/UserInterfaceState.xcuserstate b/Example/HIDRemoteExample.xcodeproj/project.xcworkspace/xcuserdata/felix.xcuserdatad/UserInterfaceState.xcuserstate index fb2c699..a982fc6 100644 Binary files a/Example/HIDRemoteExample.xcodeproj/project.xcworkspace/xcuserdata/felix.xcuserdatad/UserInterfaceState.xcuserstate and b/Example/HIDRemoteExample.xcodeproj/project.xcworkspace/xcuserdata/felix.xcuserdatad/UserInterfaceState.xcuserstate differ diff --git a/Example/HIDRemoteExample.xcodeproj/xcuserdata/felix.xcuserdatad/xcschemes/HIDRemoteExample.xcscheme b/Example/HIDRemoteExample.xcodeproj/xcuserdata/felix.xcuserdatad/xcschemes/HIDRemoteExample.xcscheme new file mode 100644 index 0000000..8525620 --- /dev/null +++ b/Example/HIDRemoteExample.xcodeproj/xcuserdata/felix.xcuserdatad/xcschemes/HIDRemoteExample.xcscheme @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Example/HIDRemoteExample.xcodeproj/xcuserdata/felix.xcuserdatad/xcschemes/xcschememanagement.plist b/Example/HIDRemoteExample.xcodeproj/xcuserdata/felix.xcuserdatad/xcschemes/xcschememanagement.plist new file mode 100644 index 0000000..7080504 --- /dev/null +++ b/Example/HIDRemoteExample.xcodeproj/xcuserdata/felix.xcuserdatad/xcschemes/xcschememanagement.plist @@ -0,0 +1,22 @@ + + + + + SchemeUserState + + HIDRemoteExample.xcscheme + + orderHint + 0 + + + SuppressBuildableAutocreation + + 8D1107260486CEB800E47090 + + primary + + + + + diff --git a/HIDRemote/HIDRemote.h b/HIDRemote/HIDRemote.h old mode 100644 new mode 100755 index 0c5b273..eaee92f --- a/HIDRemote/HIDRemote.h +++ b/HIDRemote/HIDRemote.h @@ -1,32 +1,32 @@ // -// HIDRemote.h -// HIDRemote V1.4 (18th February 2015) +// HIDRemote.m +// HIDRemote V1.6 (27th September 2017) // // Created by Felix Schwarz on 06.04.07. -// Copyright 2007-2015 IOSPIRIT GmbH. All rights reserved. +// Copyright 2007-2017 IOSPIRIT GmbH. All rights reserved. // // The latest version of this class is available at // http://www.iospirit.com/developers/hidremote/ // // ** LICENSE ************************************************************************* // -// Copyright (c) 2007-2014 IOSPIRIT GmbH (http://www.iospirit.com/) +// Copyright (c) 2007-2017 IOSPIRIT GmbH (http://www.iospirit.com/) // All rights reserved. -// +// // Redistribution and use in source and binary forms, with or without modification, // are permitted provided that the following conditions are met: -// +// // * Redistributions of source code must retain the above copyright notice, this list // of conditions and the following disclaimer. -// +// // * Redistributions in binary form must reproduce the above copyright notice, this // list of conditions and the following disclaimer in the documentation and/or other // materials provided with the distribution. -// +// // * Neither the name of IOSPIRIT GmbH nor the names of its contributors may be used to // endorse or promote products derived from this software without specific prior // written permission. -// +// // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES // OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT @@ -40,7 +40,6 @@ // // ************************************************************************************ - // ************************************************************************************ // ********************************** DOCUMENTATION *********************************** // ************************************************************************************ @@ -67,6 +66,15 @@ #include #endif +#ifndef HIDREMOTE_THREADSAFETY_HARDENED_NOTIFICATION_HANDLING + #if MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5 + // Enable thread-safe notification handling by default if deploying to OS X >= 10.5 + #define HIDREMOTE_THREADSAFETY_HARDENED_NOTIFICATION_HANDLING 1 + #else + #define HIDREMOTE_THREADSAFETY_HARDENED_NOTIFICATION_HANDLING 0 + #endif +#endif + #include #include #include @@ -81,8 +89,10 @@ #include #include -#pragma mark -- Enums / Codes -- +#pragma mark - Enums / Codes +#ifndef HID_REMOTE_MODE_ENUM +#define HID_REMOTE_MODE_ENUM 1 typedef enum { kHIDRemoteModeNone = 0L, @@ -94,6 +104,7 @@ typedef enum kHIDRemoteModeExclusiveAuto // Try to acquire an exclusive lock on the remote whenever the application has focus. Temporarily release control over the // remote when another application has focus (RECOMMENDED) } HIDRemoteMode; +#endif /* HID_REMOTE_MODE_ENUM */ typedef enum { @@ -161,7 +172,7 @@ typedef enum @class HIDRemote; -#pragma mark -- Delegate protocol (mandatory) -- +#pragma mark - Delegate protocol (mandatory) @protocol HIDRemoteDelegate // Notification of button events @@ -209,8 +220,7 @@ typedef enum @end -#pragma mark -- Actual header file for class -- - +#pragma mark - Actual header file for class @interface HIDRemote : NSObject { // IOMasterPort @@ -270,21 +280,21 @@ typedef enum BOOL _isStopping; // Thread safety - #ifdef HIDREMOTE_THREADSAFETY_HARDENED_NOTIFICATION_HANDLING /* #define HIDREMOTE_THREADSAFETY_HARDENED_NOTIFICATION_HANDLING if you're running your HIDRemote instance on a background thread (requires OS X 10.5 or later) */ + #if HIDREMOTE_THREADSAFETY_HARDENED_NOTIFICATION_HANDLING /* #define HIDREMOTE_THREADSAFETY_HARDENED_NOTIFICATION_HANDLING if you're running your HIDRemote instance on a background thread (requires OS X 10.5 or later) */ NSThread *_runOnThread; #endif } -#pragma mark -- PUBLIC: Shared HID Remote -- +#pragma mark - PUBLIC: Shared HID Remote + (HIDRemote *)sharedHIDRemote; -#pragma mark -- PUBLIC: System Information -- +#pragma mark - PUBLIC: System Information + (BOOL)isCandelairInstalled; + (BOOL)isCandelairInstallationRequiredForRemoteMode:(HIDRemoteMode)remoteMode; + (SInt32)OSXVersion; - (HIDRemoteAluminumRemoteSupportLevel)aluminiumRemoteSystemSupportLevel; -#pragma mark -- PUBLIC: Interface / API -- +#pragma mark - PUBLIC: Interface / API - (BOOL)startRemoteControl:(HIDRemoteMode)hidRemoteMode; - (void)stopRemoteControl; @@ -307,7 +317,7 @@ typedef enum - (void)setUnusedButtonCodes:(NSArray *)newArrayWithUnusedButtonCodesAsNSNumbers; - (NSArray *)unusedButtonCodes; -#pragma mark -- PUBLIC: Expert APIs -- +#pragma mark - PUBLIC: Expert APIs - (void)setEnableSecureEventInputWorkaround:(BOOL)newEnableSecureEventInputWorkaround; - (BOOL)enableSecureEventInputWorkaround; @@ -317,28 +327,28 @@ typedef enum - (BOOL)isApplicationTerminating; - (BOOL)isStopping; -#pragma mark -- PRIVATE: HID Event handling -- +#pragma mark - PRIVATE: HID Event handling - (void)_handleButtonCode:(HIDRemoteButtonCode)buttonCode isPressed:(BOOL)isPressed hidAttribsDict:(NSMutableDictionary *)hidAttribsDict; - (void)_sendButtonCode:(HIDRemoteButtonCode)buttonCode isPressed:(BOOL)isPressed hidAttribsDict:(NSMutableDictionary *)hidAttribsDict; - (void)_hidEventFor:(io_service_t)hidDevice from:(IOHIDQueueInterface **)interface withResult:(IOReturn)result; -#pragma mark -- PRIVATE: Service setup and destruction -- +#pragma mark - PRIVATE: Service setup and destruction - (BOOL)_prematchService:(io_object_t)service; - (HIDRemoteButtonCode)buttonCodeForUsage:(unsigned int)usage usagePage:(unsigned int)usagePage; - (BOOL)_setupService:(io_object_t)service; - (void)_destructService:(io_object_t)service; -#pragma mark -- PRIVATE: Distributed notifiations handling -- +#pragma mark - PRIVATE: Distributed notifiations handling - (void)_postStatusWithAction:(NSString *)action; - (void)_handleNotifications:(NSNotification *)notification; - (void)_setSendStatusNotifications:(BOOL)doSend; - (BOOL)_sendStatusNotifications; -#pragma mark -- PRIVATE: Application becomes active / inactive handling for kHIDRemoteModeExclusiveAuto -- +#pragma mark - PRIVATE: Application becomes active / inactive handling for kHIDRemoteModeExclusiveAuto - (void)_appStatusChanged:(NSNotification *)notification; - (void)_delayedAutoRecovery:(NSTimer *)aTimer; -#pragma mark -- PRIVATE: Notification handling -- +#pragma mark - PRIVATE: Notification handling - (void)_serviceMatching:(io_iterator_t)iterator; - (void)_serviceNotificationFor:(io_service_t)service messageType:(natural_t)messageType messageArgument:(void *)messageArgument; - (void)_updateSessionInformation; @@ -346,12 +356,12 @@ typedef enum @end -#pragma mark -- Information attribute keys -- +#pragma mark - Information attribute keys extern NSString *kHIDRemoteManufacturer; extern NSString *kHIDRemoteProduct; extern NSString *kHIDRemoteTransport; -#pragma mark -- Internal/Expert attribute keys (AKA: don't touch these unless you really, really, REALLY know what you do) -- +#pragma mark - Internal/Expert attribute keys (AKA: don't touch these unless you really, really, REALLY know what you do) extern NSString *kHIDRemoteCFPluginInterface; extern NSString *kHIDRemoteHIDDeviceInterface; extern NSString *kHIDRemoteCookieButtonCodeLUT; @@ -365,14 +375,14 @@ extern NSString *kHIDRemoteSimulateHoldEventsOriginButtonCode; extern NSString *kHIDRemoteAluminumRemoteSupportLevel; extern NSString *kHIDRemoteAluminumRemoteSupportOnDemand; -#pragma mark -- Distributed notifications -- +#pragma mark - Distributed notifications extern NSString *kHIDRemoteDNHIDRemotePing; extern NSString *kHIDRemoteDNHIDRemoteRetry; extern NSString *kHIDRemoteDNHIDRemoteStatus; extern NSString *kHIDRemoteDNHIDRemoteRetryGlobalObject; -#pragma mark -- Distributed notifications userInfo keys and values -- +#pragma mark - Distributed notifications userInfo keys and values extern NSString *kHIDRemoteDNStatusHIDRemoteVersionKey; extern NSString *kHIDRemoteDNStatusPIDKey; extern NSString *kHIDRemoteDNStatusModeKey; @@ -385,8 +395,11 @@ extern NSString *kHIDRemoteDNStatusActionStop; extern NSString *kHIDRemoteDNStatusActionUpdate; extern NSString *kHIDRemoteDNStatusActionNoNeed; -#pragma mark -- Driver compatibility flags -- +#pragma mark - Driver compatibility flags +#ifndef HID_REMOTE_COMPATIBILITY_FLAGS_ENUM +#define HID_REMOTE_COMPATIBILITY_FLAGS_ENUM 1 typedef enum { kHIDRemoteCompatibilityFlagsStandardHIDRemoteDevice = 1L, } HIDRemoteCompatibilityFlags; +#endif /* HID_REMOTE_COMPATIBILITY_FLAGS_ENUM */ diff --git a/HIDRemote/HIDRemote.m b/HIDRemote/HIDRemote.m old mode 100644 new mode 100755 index 0f54b75..16e704b --- a/HIDRemote/HIDRemote.m +++ b/HIDRemote/HIDRemote.m @@ -1,16 +1,16 @@ // // HIDRemote.m -// HIDRemote V1.4 (18th February 2015) +// HIDRemote V1.6 (27th September 2017) // // Created by Felix Schwarz on 06.04.07. -// Copyright 2007-2015 IOSPIRIT GmbH. All rights reserved. +// Copyright 2007-2017 IOSPIRIT GmbH. All rights reserved. // // The latest version of this class is available at // http://www.iospirit.com/developers/hidremote/ // // ** LICENSE ************************************************************************* // -// Copyright (c) 2007-2014 IOSPIRIT GmbH (http://www.iospirit.com/) +// Copyright (c) 2007-2017 IOSPIRIT GmbH (http://www.iospirit.com/) // All rights reserved. // // Redistribution and use in source and binary forms, with or without modification, @@ -51,6 +51,37 @@ #import "HIDRemote.h" +// ARC support +#if !__has_feature(objc_arc) + #define HIDRemoteRetain(object) [object retain] + #define HIDRemoteRetained(object) [object retain] + #define HIDRemoteRelease(object) [object release] + #define HIDRemoteReleaseNil(object) [object release]; object=nil + #define HIDRemoteAutoreleased(object) [object autorelease] + #define HIDRemoteSuperDealloc(object) [super dealloc] + + #define HIDRemoteAutoreleasePoolOpen() NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + #define HIDRemoteAutoreleasePoolClose() [pool release]; + + #define __HIDRemoteBridge + #define HIDRemoteBridgingRelease + #define HIDRemoteBridgingRetain +#else /* !__has_feature(objc_arc) */ + #define HIDRemoteRetain(object) + #define HIDRemoteRetained(object) object + #define HIDRemoteRelease(object) + #define HIDRemoteReleaseNil(object) object=nil + #define HIDRemoteAutoreleased(object) object + #define HIDRemoteSuperDealloc(object) + + #define HIDRemoteAutoreleasePoolOpen() @autoreleasepool { + #define HIDRemoteAutoreleasePoolClose() } + + #define __HIDRemoteBridge __bridge + #define HIDRemoteBridgingRelease CFBridgingRelease + #define HIDRemoteBridgingRetain CFBridgingRetain +#endif + // Callback Prototypes static void HIDEventCallback( void * target, IOReturn result, @@ -91,8 +122,8 @@ - (id)init { if ((self = [super init]) != nil) { - #ifdef HIDREMOTE_THREADSAFETY_HARDENED_NOTIFICATION_HANDLING - _runOnThread = [[NSThread currentThread] retain]; + #if HIDREMOTE_THREADSAFETY_HARDENED_NOTIFICATION_HANDLING + _runOnThread = HIDRemoteRetained([NSThread currentThread]); #endif // Detect application becoming active/inactive @@ -148,19 +179,16 @@ - (void)dealloc if (_unusedButtonCodes != nil) { - [_unusedButtonCodes release]; - _unusedButtonCodes = nil; + HIDRemoteReleaseNil(_unusedButtonCodes); } - #ifdef HIDREMOTE_THREADSAFETY_HARDENED_NOTIFICATION_HANDLING - [_runOnThread release]; - _runOnThread = nil; + #if HIDREMOTE_THREADSAFETY_HARDENED_NOTIFICATION_HANDLING + HIDRemoteReleaseNil(_runOnThread); #endif - [_pidString release]; - _pidString = nil; + HIDRemoteReleaseNil(_pidString); - [super dealloc]; + HIDRemoteSuperDealloc(); } #pragma mark - PUBLIC: System Information @@ -323,7 +351,7 @@ - (BOOL)startRemoteControl:(HIDRemoteMode)hidRemoteMode rootService, kIOBusyInterest, SecureInputNotificationCallback, - (void *)self, + (__HIDRemoteBridge void *)self, &_secureInputNotification); if (kernReturn != kIOReturnSuccess) { break; } @@ -344,7 +372,7 @@ - (BOOL)startRemoteControl:(HIDRemoteMode)hidRemoteMode kIOFirstMatchNotification, matchDict, // one reference count consumed by this call ServiceMatchingCallback, - (void *) self, + (__HIDRemoteBridge void *) self, &_matchingServicesIterator); if (kernReturn != kIOReturnSuccess) { break; } @@ -390,8 +418,7 @@ - (void)stopRemoteControl if (_autoRecoveryTimer!=nil) { [_autoRecoveryTimer invalidate]; - [_autoRecoveryTimer release]; - _autoRecoveryTimer = nil; + HIDRemoteReleaseNil(_autoRecoveryTimer); } if (_serviceAttribMap!=nil) @@ -409,12 +436,10 @@ - (void)stopRemoteControl serviceCount++; }; - [cloneDict release]; - cloneDict = nil; + HIDRemoteReleaseNil(cloneDict); } - [_serviceAttribMap release]; - _serviceAttribMap = nil; + HIDRemoteReleaseNil(_serviceAttribMap); } if (_matchingServicesIterator!=0) @@ -449,8 +474,7 @@ - (void)stopRemoteControl if (_returnToPID!=nil) { - [_returnToPID release]; - _returnToPID = nil; + HIDRemoteReleaseNil(_returnToPID); } if (_mode!=kHIDRemoteModeNone) @@ -498,7 +522,7 @@ - (HIDRemoteMode)startedInMode - (unsigned)activeRemoteControlCount { - return ([_serviceAttribMap count]); + return ((unsigned)[_serviceAttribMap count]); } - (SInt32)lastSeenRemoteControlID @@ -533,8 +557,8 @@ - (NSArray *)unusedButtonCodes - (void)setUnusedButtonCodes:(NSArray *)newArrayWithUnusedButtonCodesAsNSNumbers { - [newArrayWithUnusedButtonCodesAsNSNumbers retain]; - [_unusedButtonCodes release]; + HIDRemoteRetain(newArrayWithUnusedButtonCodesAsNSNumbers); + HIDRemoteRelease(_unusedButtonCodes); _unusedButtonCodes = newArrayWithUnusedButtonCodesAsNSNumbers; @@ -576,8 +600,7 @@ - (void)setExclusiveLockLendingEnabled:(BOOL)newExclusiveLockLendingEnabled { [[NSDistributedNotificationCenter defaultCenter] removeObserver:self name:kHIDRemoteDNHIDRemoteStatus object:nil]; - [_waitForReturnByPID release]; - _waitForReturnByPID = nil; + HIDRemoteReleaseNil(_waitForReturnByPID); } } } @@ -610,7 +633,7 @@ - (BOOL)isStopping #pragma mark - PRIVATE: Application becomes active / inactive handling for kHIDRemoteModeExclusiveAuto - (void)_appStatusChanged:(NSNotification *)notification { - #ifdef HIDREMOTE_THREADSAFETY_HARDENED_NOTIFICATION_HANDLING + #if HIDREMOTE_THREADSAFETY_HARDENED_NOTIFICATION_HANDLING if ([self respondsToSelector:@selector(performSelector:onThread:withObject:waitUntilDone:)]) // OS X 10.5+ only { if ([NSThread currentThread] != _runOnThread) @@ -642,8 +665,7 @@ - (void)_appStatusChanged:(NSNotification *)notification if (_autoRecoveryTimer!=nil) { [_autoRecoveryTimer invalidate]; - [_autoRecoveryTimer release]; - _autoRecoveryTimer = nil; + HIDRemoteReleaseNil(_autoRecoveryTimer); } if ([[notification name] isEqual:NSApplicationDidBecomeActiveNotification]) @@ -685,8 +707,7 @@ - (void)_appStatusChanged:(NSNotification *)notification - (void)_delayedAutoRecovery:(NSTimer *)aTimer { [_autoRecoveryTimer invalidate]; - [_autoRecoveryTimer release]; - _autoRecoveryTimer = nil; + HIDRemoteReleaseNil(_autoRecoveryTimer); if (_autoRecover) { @@ -722,7 +743,7 @@ - (void)_handleNotifications:(NSNotification *)notification { NSString *notificationName; - #ifdef HIDREMOTE_THREADSAFETY_HARDENED_NOTIFICATION_HANDLING + #if HIDREMOTE_THREADSAFETY_HARDENED_NOTIFICATION_HANDLING if ([self respondsToSelector:@selector(performSelector:onThread:withObject:waitUntilDone:)]) // OS X 10.5+ only { if ([NSThread currentThread] != _runOnThread) @@ -778,15 +799,14 @@ - (void)_handleNotifications:(NSNotification *)notification _isRestarting = YES; [self stopRemoteControl]; - [_returnToPID release]; - _returnToPID = nil; + HIDRemoteReleaseNil(_returnToPID); [self startRemoteControl:restartInMode]; _isRestarting = NO; if (restartInMode != kHIDRemoteModeShared) { - _returnToPID = [[[notification userInfo] objectForKey:kHIDRemoteDNStatusPIDKey] retain]; + _returnToPID = HIDRemoteRetained([[notification userInfo] objectForKey:kHIDRemoteDNStatusPIDKey]); } } } @@ -794,9 +814,9 @@ - (void)_handleNotifications:(NSNotification *)notification { NSNumber *cacheReturnPID = _returnToPID; - _returnToPID = [[[notification userInfo] objectForKey:kHIDRemoteDNStatusPIDKey] retain]; + _returnToPID = HIDRemoteRetained([[notification userInfo] objectForKey:kHIDRemoteDNStatusPIDKey]); [self _postStatusWithAction:kHIDRemoteDNStatusActionNoNeed]; - [_returnToPID release]; + HIDRemoteRelease(_returnToPID); _returnToPID = cacheReturnPID; } @@ -842,8 +862,7 @@ - (void)_handleNotifications:(NSNotification *)notification { if ([pidNumber isEqual:_waitForReturnByPID] && ([returnToPIDNumber intValue] == getpid())) { - [_waitForReturnByPID release]; - _waitForReturnByPID = nil; + HIDRemoteReleaseNil(_waitForReturnByPID); if (([self delegate] != nil) && ([[self delegate] respondsToSelector:@selector(hidRemote:exclusiveLockReleasedByApplicationWithInfo:)])) @@ -877,8 +896,8 @@ - (void)_handleNotifications:(NSNotification *)notification if (lendLock) { - [_waitForReturnByPID release]; - _waitForReturnByPID = [originPID retain]; + HIDRemoteRelease(_waitForReturnByPID); + _waitForReturnByPID = HIDRemoteRetained(originPID); if (_waitForReturnByPID != nil) { @@ -922,7 +941,7 @@ - (BOOL)_prematchService:(io_object_t)service if (service != 0) { // IOClass matching - if ((ioClass = (NSString *)IORegistryEntryCreateCFProperty((io_registry_entry_t)service, + if ((ioClass = (__HIDRemoteBridge NSString *)IORegistryEntryCreateCFProperty((io_registry_entry_t)service, CFSTR(kIOClassKey), kCFAllocatorDefault, 0)) != nil) @@ -955,7 +974,7 @@ - (BOOL)_prematchService:(io_object_t)service } // Match on services that claim compatibility with the HID Remote class (Candelair or third-party) by having a property of CandelairHIDRemoteCompatibilityMask = 1 - if ((candelairHIDRemoteCompatibilityMask = (NSNumber *)IORegistryEntryCreateCFProperty((io_registry_entry_t)service, CFSTR("CandelairHIDRemoteCompatibilityMask"), kCFAllocatorDefault, 0)) != nil) + if ((candelairHIDRemoteCompatibilityMask = (__HIDRemoteBridge NSNumber *)IORegistryEntryCreateCFProperty((io_registry_entry_t)service, CFSTR("CandelairHIDRemoteCompatibilityMask"), kCFAllocatorDefault, 0)) != nil) { if ([candelairHIDRemoteCompatibilityMask isKindOfClass:[NSNumber class]]) { @@ -1017,6 +1036,14 @@ - (HIDRemoteButtonCode)buttonCodeForUsage:(unsigned int)usage usagePage:(unsigne case kHIDUsage_Csmr_Menu: buttonCode = kHIDRemoteButtonCodeMenuHold; break; + + case kHIDUsage_Csmr_VolumeIncrement: + buttonCode = kHIDRemoteButtonCodeUp; + break; + + case kHIDUsage_Csmr_VolumeDecrement: + buttonCode = kHIDRemoteButtonCodeDown; + break; } break; @@ -1195,17 +1222,14 @@ - (BOOL)_setupService:(io_object_t)service nil]; { - UInt32 i, hidElementCnt = CFArrayGetCount(hidElements); + UInt32 i, hidElementCnt = (UInt32)CFArrayGetCount(hidElements); NSMutableDictionary *cookieButtonCodeLUT = [[NSMutableDictionary alloc] init]; NSMutableDictionary *cookieCount = [[NSMutableDictionary alloc] init]; if ((cookieButtonCodeLUT==nil) || (cookieCount==nil)) { - [cookieButtonCodeLUT release]; - cookieButtonCodeLUT = nil; - - [cookieCount release]; - cookieCount = nil; + HIDRemoteReleaseNil(cookieButtonCodeLUT); + HIDRemoteReleaseNil(cookieCount); error = [NSError errorWithDomain:NSMachErrorDomain code:kIOReturnError userInfo:nil]; errorCode = 7; @@ -1264,9 +1288,9 @@ - (BOOL)_setupService:(io_object_t)service #include "HIDRemoteAdditions.h" #undef _HIDREMOTE_EXTENSIONS_SECTION #endif /* _HIDREMOTE_EXTENSIONS */ - - [buttonCodeNumber release]; - [pairString release]; + + HIDRemoteRelease(buttonCodeNumber); + HIDRemoteRelease(pairString); } } } @@ -1274,11 +1298,8 @@ - (BOOL)_setupService:(io_object_t)service // Compare number of *unique* matches (thus the cookieCount dictionary) with required minimum if ([cookieCount count] < 10) { - [cookieButtonCodeLUT release]; - cookieButtonCodeLUT = nil; - - [cookieCount release]; - cookieCount = nil; + HIDRemoteReleaseNil(cookieButtonCodeLUT); + HIDRemoteReleaseNil(cookieCount); error = [NSError errorWithDomain:NSMachErrorDomain code:kIOReturnError userInfo:nil]; errorCode = 8; @@ -1288,11 +1309,8 @@ - (BOOL)_setupService:(io_object_t)service [hidAttribsDict setObject:cookieButtonCodeLUT forKey:kHIDRemoteCookieButtonCodeLUT]; - [cookieButtonCodeLUT release]; - cookieButtonCodeLUT = nil; - - [cookieCount release]; - cookieCount = nil; + HIDRemoteReleaseNil(cookieButtonCodeLUT); + HIDRemoteReleaseNil(cookieCount); } // Finish setup of IOHIDQueueInterface with CFRunLoop @@ -1304,7 +1322,7 @@ - (BOOL)_setupService:(io_object_t)service break; } - returnCode = (*hidQueueInterface)->setEventCallout(hidQueueInterface, HIDEventCallback, (void *)((intptr_t)service), (void *)self); + returnCode = (*hidQueueInterface)->setEventCallout(hidQueueInterface, HIDEventCallback, (void *)((intptr_t)service), (__HIDRemoteBridge void *)self); if (returnCode != kIOReturnSuccess) { error = [NSError errorWithDomain:NSMachErrorDomain code:returnCode userInfo:nil]; @@ -1332,7 +1350,7 @@ - (BOOL)_setupService:(io_object_t)service service, kIOGeneralInterest, ServiceNotificationCallback, - self, + (__HIDRemoteBridge void *)(self), &serviceNotification); if ((returnCode != kIOReturnSuccess) || (serviceNotification==0)) { @@ -1364,7 +1382,7 @@ - (BOOL)_setupService:(io_object_t)service { if (CFGetTypeID(product) == CFStringGetTypeID()) { - [hidAttribsDict setObject:(NSString *)product forKey:kHIDRemoteProduct]; + [hidAttribsDict setObject:(__HIDRemoteBridge NSString *)product forKey:kHIDRemoteProduct]; } CFRelease(product); @@ -1377,7 +1395,7 @@ - (BOOL)_setupService:(io_object_t)service { if (CFGetTypeID(manufacturer) == CFStringGetTypeID()) { - [hidAttribsDict setObject:(NSString *)manufacturer forKey:kHIDRemoteManufacturer]; + [hidAttribsDict setObject:(__HIDRemoteBridge NSString *)manufacturer forKey:kHIDRemoteManufacturer]; } CFRelease(manufacturer); @@ -1390,7 +1408,7 @@ - (BOOL)_setupService:(io_object_t)service { if (CFGetTypeID(transport) == CFStringGetTypeID()) { - [hidAttribsDict setObject:(NSString *)transport forKey:kHIDRemoteTransport]; + [hidAttribsDict setObject:(__HIDRemoteBridge NSString *)transport forKey:kHIDRemoteTransport]; } CFRelease(transport); @@ -1413,14 +1431,14 @@ - (BOOL)_setupService:(io_object_t)service // There is => request the driver to enable it for us if (IORegistryEntrySetCFProperty((io_registry_entry_t)service, CFSTR("EnableAluminumRemoteSupportForMe"), - [NSDictionary dictionaryWithObjectsAndKeys: + (__HIDRemoteBridge CFTypeRef)([NSDictionary dictionaryWithObjectsAndKeys: [NSNumber numberWithLongLong:(long long)getpid()], @"pid", [NSNumber numberWithLongLong:(long long)getuid()], @"uid", - nil]) == kIOReturnSuccess) + nil])) == kIOReturnSuccess) { if (CFGetTypeID(aluSupport) == CFNumberGetTypeID()) { - supportLevel = (HIDRemoteAluminumRemoteSupportLevel) [(NSNumber *)aluSupport intValue]; + supportLevel = (HIDRemoteAluminumRemoteSupportLevel) [(__HIDRemoteBridge NSNumber *)aluSupport intValue]; } [hidAttribsDict setObject:[NSNumber numberWithBool:YES] forKey:kHIDRemoteAluminumRemoteSupportOnDemand]; @@ -1439,7 +1457,7 @@ - (BOOL)_setupService:(io_object_t)service { if (CFGetTypeID(aluSupport) == CFNumberGetTypeID()) { - supportLevel = (HIDRemoteAluminumRemoteSupportLevel) [(NSNumber *)aluSupport intValue]; + supportLevel = (HIDRemoteAluminumRemoteSupportLevel) [(__HIDRemoteBridge NSNumber *)aluSupport intValue]; } CFRelease(aluSupport); @@ -1453,7 +1471,7 @@ - (BOOL)_setupService:(io_object_t)service kCFAllocatorDefault, 0)) != nil) { - if ([(NSString *)ioKitClassName isEqual:@"AppleIRController"]) + if ([(__HIDRemoteBridge NSString *)ioKitClassName isEqual:@"AppleIRController"]) { if ([HIDRemote OSXVersion] >= 0x1062) { @@ -1486,9 +1504,8 @@ - (BOOL)_setupService:(io_object_t)service { [((NSObject *)[self delegate]) hidRemote:self foundNewHardwareWithAttributes:hidAttribsDict]; } - - [hidAttribsDict release]; - hidAttribsDict = nil; + + HIDRemoteReleaseNil(hidAttribsDict); return(YES); @@ -1536,8 +1553,7 @@ - (BOOL)_setupService:(io_object_t)service if (hidAttribsDict!=nil) { - [hidAttribsDict release]; - hidAttribsDict = nil; + HIDRemoteReleaseNil(hidAttribsDict); } if (hidElements!=NULL) @@ -1598,7 +1614,7 @@ - (void)_destructService:(io_object_t)service cookieButtonMap = (NSMutableDictionary *) [serviceDict objectForKey:kHIDRemoteCookieButtonCodeLUT]; simulateHoldTimer = (NSTimer *) [serviceDict objectForKey:kHIDRemoteSimulateHoldEventsTimer]; - [serviceDict retain]; + HIDRemoteRetain(serviceDict); [_serviceAttribMap removeObjectForKey:serviceValue]; if (([serviceDict objectForKey:kHIDRemoteAluminumRemoteSupportOnDemand]!=nil) && [[serviceDict objectForKey:kHIDRemoteAluminumRemoteSupportOnDemand] boolValue] && (theService != 0)) @@ -1606,10 +1622,10 @@ - (void)_destructService:(io_object_t)service // We previously requested the driver to enable Aluminum Remote support for us. Tell it to turn it off again - now that we no longer need it IORegistryEntrySetCFProperty( (io_registry_entry_t)theService, CFSTR("DisableAluminumRemoteSupportForMe"), - [NSDictionary dictionaryWithObjectsAndKeys: - [NSNumber numberWithLongLong:(long long)getpid()], @"pid", - [NSNumber numberWithLongLong:(long long)getuid()], @"uid", - nil]); + (__HIDRemoteBridge CFTypeRef)([NSDictionary dictionaryWithObjectsAndKeys: + [NSNumber numberWithLongLong:(long long)getpid()], @"pid", + [NSNumber numberWithLongLong:(long long)getuid()], @"uid", + nil])); } if (([self delegate]!=nil) && @@ -1673,7 +1689,7 @@ - (void)_destructService:(io_object_t)service IOObjectRelease(theService); } - [serviceDict release]; + HIDRemoteRelease(serviceDict); } } @@ -1728,7 +1744,7 @@ - (void)_handleButtonCode:(HIDRemoteButtonCode)buttonCode isPressed:(BOOL)isPres // is designed to be also compatible with 10.4. CFRunLoopTimerRef is "toll-free-bridged" with NSTimer since 10.0. CFRunLoopAddTimer(CFRunLoopGetCurrent(), (CFRunLoopTimerRef)shTimer, kCFRunLoopCommonModes); - [shTimer release]; + HIDRemoteRelease(shTimer); break; } @@ -1813,7 +1829,7 @@ - (void)_sendButtonCode:(HIDRemoteButtonCode)buttonCode isPressed:(BOOL)isPresse - (void)_hidEventFor:(io_service_t)hidDevice from:(IOHIDQueueInterface **)interface withResult:(IOReturn)result { - NSMutableDictionary *hidAttribsDict = [[[_serviceAttribMap objectForKey:[NSNumber numberWithUnsignedInt:(unsigned int)hidDevice]] retain] autorelease]; + NSMutableDictionary *hidAttribsDict = HIDRemoteAutoreleased(HIDRemoteRetained([_serviceAttribMap objectForKey:[NSNumber numberWithUnsignedInt:(unsigned int)hidDevice]])); if (hidAttribsDict!=nil) { @@ -1937,7 +1953,7 @@ - (void)_updateSessionInformation if ((rootService = IORegistryGetRootEntry(_masterPort)) != 0) { - if ((consoleUsersArray = (NSArray *)IORegistryEntryCreateCFProperty((io_registry_entry_t)rootService, CFSTR("IOConsoleUsers"), kCFAllocatorDefault, 0)) != nil) + if ((consoleUsersArray = (__HIDRemoteBridge NSArray *)IORegistryEntryCreateCFProperty((io_registry_entry_t)rootService, CFSTR("IOConsoleUsers"), kCFAllocatorDefault, 0)) != nil) { if ([consoleUsersArray isKindOfClass:[NSArray class]]) // Be careful - ensure this really is an array { @@ -2055,7 +2071,7 @@ - (void)_computerDidWake:(NSNotification *)aNotification if (NSAppKitVersionNumber >= 1187) #endif { - #ifdef HIDREMOTE_THREADSAFETY_HARDENED_NOTIFICATION_HANDLING + #if HIDREMOTE_THREADSAFETY_HARDENED_NOTIFICATION_HANDLING if ([self respondsToSelector:@selector(performSelector:onThread:withObject:waitUntilDone:)]) // OS X 10.5+ only { if ([NSThread currentThread] != _runOnThread) @@ -2079,24 +2095,26 @@ static void HIDEventCallback( void * target, void * refCon, void * sender) { - HIDRemote *hidRemote = (HIDRemote *)refCon; - NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + HIDRemote *hidRemote = (__HIDRemoteBridge HIDRemote *)refCon; + + HIDRemoteAutoreleasePoolOpen(); [hidRemote _hidEventFor:(io_service_t)((intptr_t)target) from:(IOHIDQueueInterface**)sender withResult:(IOReturn)result]; - [pool release]; + HIDRemoteAutoreleasePoolClose(); } static void ServiceMatchingCallback( void *refCon, io_iterator_t iterator) { - HIDRemote *hidRemote = (HIDRemote *)refCon; - NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + HIDRemote *hidRemote = (__HIDRemoteBridge HIDRemote *)refCon; + + HIDRemoteAutoreleasePoolOpen(); [hidRemote _serviceMatching:iterator]; - [pool release]; + HIDRemoteAutoreleasePoolClose(); } static void ServiceNotificationCallback(void * refCon, @@ -2104,14 +2122,15 @@ static void ServiceNotificationCallback(void * refCon, natural_t messageType, void * messageArgument) { - HIDRemote *hidRemote = (HIDRemote *)refCon; - NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + HIDRemote *hidRemote = (__HIDRemoteBridge HIDRemote *)refCon; + + HIDRemoteAutoreleasePoolOpen(); [hidRemote _serviceNotificationFor:service messageType:messageType messageArgument:messageArgument]; - [pool release]; + HIDRemoteAutoreleasePoolClose(); } static void SecureInputNotificationCallback( void * refCon, @@ -2119,14 +2138,15 @@ static void SecureInputNotificationCallback( void * refCon, natural_t messageType, void * messageArgument) { - HIDRemote *hidRemote = (HIDRemote *)refCon; - NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + HIDRemote *hidRemote = (__HIDRemoteBridge HIDRemote *)refCon; + + HIDRemoteAutoreleasePoolOpen(); [hidRemote _secureInputNotificationFor:service messageType:messageType messageArgument:messageArgument]; - [pool release]; + HIDRemoteAutoreleasePoolClose(); } // Attribute dictionary keys diff --git a/LICENSE.txt b/LICENSE.txt index fbafd75..0638b50 100644 --- a/LICENSE.txt +++ b/LICENSE.txt @@ -1,4 +1,4 @@ -Copyright (c) 2007-2015 IOSPIRIT GmbH (http://www.iospirit.com/) +Copyright (c) 2007-2017 IOSPIRIT GmbH (http://www.iospirit.com/) All rights reserved. Redistribution and use in source and binary forms, with or without modification, @@ -24,4 +24,4 @@ TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH -DAMAGE. \ No newline at end of file +DAMAGE. diff --git a/README.markdown b/README.markdown index e58a3e1..7561a91 100644 --- a/README.markdown +++ b/README.markdown @@ -1,21 +1,21 @@ ## About the HIDRemote class -The HIDRemote Objective-C class provides your application with access to the Apple® Remote IR Receiver under OS X 10.4 (Tiger) up to OS X 10.10 (Yosemite). It is available under a BSD-style license. +The HIDRemote Objective-C class provides your application with access to the Apple Remote IR Receiver under OS X 10.4 (Tiger) up to OS X 10.13 (High Sierra). It is available under a BSD-style license. ## Why you'll want to use the HIDRemote class -The HIDRemote class was developed with the needs of users, standalone applications, media center software, background applications, remote control solutions, drivers and Apple® Remote emulators in mind. The primary goals are to maximize compatibility, interoperability, future-proofness and user-friendlyness. In fact, the more developers use it for supporting the Apple® Remote in their applications, the better the system-wide user experience will be for everyone. +The HIDRemote class was developed with the needs of users, standalone applications, media center software, background applications, remote control solutions, drivers and Apple Remote emulators in mind. The primary goals are to maximize compatibility, interoperability, future-proofness and user-friendlyness. In fact, the more developers use it for supporting the Apple Remote in their applications, the better the system-wide user experience will be for everyone. ## Features ### Smart, flexible event handling The HIDRemote class uses the HID system supplied information about the IR Receiver HID Device to build a dynamic button-cookie map it can then use to understand incoming events regardless of the layout of the HID device's HID descriptor. Hence, HIDRemote doesn't need any OS release or driver specific event handling code, making it a user-friendly and flexible choice for developers that's well prepared for the future. -### Support for the white (plastic) and aluminum Apple® Remote +### Support for the white (plastic) and aluminum Apple Remote The HIDRemote class auto-detects the remote in use and allows you to determine the remote control type with a single call. Your delegate receives messages for all buttons. Under OS 10.6.2 and later, an extra button code is used for the new, additional Play/Pause button of the new aluminum version. ### Shared, exclusive and exclusive-auto modes -The HIDRemote class can share access with OS X or access it exclusively. Additionally, the exclusive-auto mode can automatically establish/relinquish exlusive access to the remote alongside the application becoming active/inactive. +The HIDRemote class can share access with OS X or access it exclusively. Additionally, the exclusive-auto mode can automatically establish/relinquish exclusive access to the remote alongside the application becoming active/inactive. ### Exclusive Lock Lending Some background applications need to have an exclusive lock on the IR Receiver to implement their task. Consequently, other applications are not able to get access to the IR Receiver (and thus the remote) at the same time. This is something that both developers and users will not want. @@ -25,18 +25,18 @@ The HIDRemote class addresses this issue with its Exclusive Lock Lending feature With this mechanism in place, users can control both the slideshow and background application in a naturally feeling way. ### Provides detailed metadata to drivers and remote control solutions for seamless integration -With the HIDRemote class, applications can "broadcast" detailed metadata about their remote control support and usage via distributed notifications. This includes the current status (turned off, shared, exlusive or exclusive-auto acccess) and an application-definable list of unused button codes. +With the HIDRemote class, applications can "broadcast" detailed metadata about their remote control support and usage via distributed notifications. This includes the current status (turned off, shared, exclusive or exclusive-auto access) and an application-definable list of unused button codes. This metadata can be used by the Exclusive Lock Lending feature, drivers and remote control solutions (such as Remote Buddy) to deliver the best possible integration and user experience. ### Support for deep sleep -The HIDRemote class will automatically re-acquire access to the IR Receiver when a Mac® wakes up from deep sleep (more widely known as "hibernation"). +The HIDRemote class will automatically re-acquire access to the IR Receiver when a Mac wakes up from deep sleep (more widely known as "hibernation"). ### Support for multiple devices -Built from ground up to support multiple devices, the HIDRemote class enables applications using it to receive button press events from more than one HID device at a time. This removes a substantial bottleneck for third party developers that wish to implement an Apple® Remote emulation as well as for developers that want their applications to be compatible with them. +Built from ground up to support multiple devices, the HIDRemote class enables applications using it to receive button press events from more than one HID device at a time. This removes a substantial bottleneck for third party developers that wish to implement an Apple Remote emulation as well as for developers that want their applications to be compatible with them. ### Built-In compatibility checks -The HIDRemote class generally works completely independant from Candelair. It, however, needs the support of Candelair under OS releases where establishing an exclusive lock on the IR Receiver is otherwise not possible (currently this is only the case under 10.6 and 10.6.1). For your convenience, the HIDRemote class provides a method that can be used to determine whether Candelair is required under a particular OS release. An example on how to use it is part of the sample code accompanying the HIDRemote class download and the HIDRemote guide. +The HIDRemote class generally works completely independent from Candelair. It, however, needs the support of Candelair under OS releases where establishing an exclusive lock on the IR Receiver is otherwise not possible (currently this is only the case under 10.6 and 10.6.1). For your convenience, the HIDRemote class provides a method that can be used to determine whether Candelair is required under a particular OS release. An example on how to use it is part of the sample code accompanying the HIDRemote class download and the HIDRemote guide. ### 32- and 64-Bit compatible -Can be used by 32- and 64-Bit applications. Compatible with 32-Bit and 64-Bit kernels. \ No newline at end of file +Can be used by 32- and 64-Bit applications. Compatible with 32-Bit and 64-Bit kernels.