aboutsummaryrefslogtreecommitdiff
path: root/tools/EventClients/Clients/OSXRemote/HIDRemote/HIDRemote.m
diff options
context:
space:
mode:
Diffstat (limited to 'tools/EventClients/Clients/OSXRemote/HIDRemote/HIDRemote.m')
-rw-r--r--tools/EventClients/Clients/OSXRemote/HIDRemote/HIDRemote.m562
1 files changed, 426 insertions, 136 deletions
diff --git a/tools/EventClients/Clients/OSXRemote/HIDRemote/HIDRemote.m b/tools/EventClients/Clients/OSXRemote/HIDRemote/HIDRemote.m
index 9b3769d304..502100250f 100644
--- a/tools/EventClients/Clients/OSXRemote/HIDRemote/HIDRemote.m
+++ b/tools/EventClients/Clients/OSXRemote/HIDRemote/HIDRemote.m
@@ -1,6 +1,6 @@
//
// HIDRemote.m
-// HIDRemote V1.0
+// HIDRemote V1.1 (13th November 2009)
//
// Created by Felix Schwarz on 06.04.07.
// Copyright 2007-2009 IOSPIRIT GmbH. All rights reserved.
@@ -40,8 +40,6 @@
//
// ************************************************************************************
-
-
// ************************************************************************************
// ********************************** DOCUMENTATION ***********************************
// ************************************************************************************
@@ -51,7 +49,6 @@
//
// ************************************************************************************
-
#import "HIDRemote.h"
// Callback Prototypes
@@ -68,6 +65,11 @@ static void ServiceNotificationCallback(void * refCon,
natural_t messageType,
void * messageArgument);
+static void SecureInputNotificationCallback( void * refCon,
+ io_service_t service,
+ natural_t messageType,
+ void * messageArgument);
+
// Shared HIDRemote instance
static HIDRemote *sHIDRemote = nil;
@@ -87,7 +89,7 @@ static HIDRemote *sHIDRemote = nil;
- (id)init
{
- if (self = [super init])
+ if ((self = [super init]) != nil)
{
// Detect application becoming active/inactive
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_appStatusChanged:) name:NSApplicationDidBecomeActiveNotification object:[NSApplication sharedApplication]];
@@ -101,12 +103,13 @@ static HIDRemote *sHIDRemote = nil;
// Enabled by default: simulate hold events for plus/minus
_simulateHoldEvents = YES;
- // Enabled by default: work around for a locking issue introduced with Security Update 2008-004 / 10.4.9 and beyond
+ // Enabled by default: work around for a locking issue introduced with Security Update 2008-004 / 10.4.9 and beyond (credit for finding this workaround goes to Martin Kahr)
_secureEventInputWorkAround = YES;
- _statusSecureEventInputWorkAroundEnabled = NO;
+ _secureInputNotification = 0;
// Initialize instance variables
_lastSeenRemoteID = -1;
+ _lastSeenModel = kHIDRemoteModelUndetermined;
_unusedButtonCodes = [[NSMutableArray alloc] init];
_exclusiveLockLending = NO;
}
@@ -171,11 +174,6 @@ static HIDRemote *sHIDRemote = nil;
// OS X 10.6(.0) and OS X 10.6.1 require the Candelair driver for to be installed,
// so that third party apps can acquire an exclusive lock on the receiver HID Device
// via IOKit.
- //
- // IMPORTANT:
- // We do not include later OS releases here, because the issue may be fixed in these.
- // We simply don't know at this point. Updated sourcecode will be available at
- // candelair.com as necessary.
switch (remoteMode)
{
@@ -194,25 +192,38 @@ static HIDRemote *sHIDRemote = nil;
return (NO);
}
-#pragma mark -- PUBLIC: Interface / API --
-- (BOOL)startRemoteControl:(HIDRemoteMode)hidRemoteMode
+- (HIDRemoteAluminumRemoteSupportLevel)aluminiumRemoteSystemSupportLevel
{
- if ((_mode == kHIDRemoteModeNone) && (hidRemoteMode != kHIDRemoteModeNone))
+ HIDRemoteAluminumRemoteSupportLevel supportLevel = kHIDRemoteAluminumRemoteSupportLevelNone;
+ NSEnumerator *attribDictsEnum;
+ NSDictionary *hidAttribsDict;
+
+ attribDictsEnum = [_serviceAttribMap objectEnumerator];
+
+ while ((hidAttribsDict = [attribDictsEnum nextObject]) != nil)
{
- kern_return_t kernReturn;
- CFMutableDictionaryRef matchDict=NULL;
+ NSNumber *deviceSupportLevel;
- // Work around a locking issue introduced with Security Update 2008-004 / 10.4.9 and beyond
- if ((_mode != kHIDRemoteModeShared) && (_secureEventInputWorkAround))
+ if ((deviceSupportLevel = [hidAttribsDict objectForKey:kHIDRemoteAluminumRemoteSupportLevel]) != nil)
{
- if (!_statusSecureEventInputWorkAroundEnabled)
+ if ([deviceSupportLevel intValue] > supportLevel)
{
- EnableSecureEventInput();
-
- // Keep track of our use of EnableSecureEventInput()/DisableSecureEventInput() to avoid count "leaks"
- _statusSecureEventInputWorkAroundEnabled = YES;
+ supportLevel = [deviceSupportLevel intValue];
}
}
+ }
+
+ return (supportLevel);
+}
+
+#pragma mark -- PUBLIC: Interface / API --
+- (BOOL)startRemoteControl:(HIDRemoteMode)hidRemoteMode
+{
+ if ((_mode == kHIDRemoteModeNone) && (hidRemoteMode != kHIDRemoteModeNone))
+ {
+ kern_return_t kernReturn;
+ CFMutableDictionaryRef matchDict=NULL;
+ io_service_t rootService;
do
{
@@ -223,7 +234,7 @@ static HIDRemote *sHIDRemote = nil;
// Setup notification port
_notifyPort = IONotificationPortCreate(_masterPort);
- if (_notifyRLSource = IONotificationPortGetRunLoopSource(_notifyPort))
+ if ((_notifyRLSource = IONotificationPortGetRunLoopSource(_notifyPort)) != NULL)
{
CFRunLoopAddSource( CFRunLoopGetCurrent(),
_notifyRLSource,
@@ -233,6 +244,27 @@ static HIDRemote *sHIDRemote = nil;
{
break;
}
+
+ // Setup SecureInput notification
+ if ((hidRemoteMode == kHIDRemoteModeExclusive) || (hidRemoteMode == kHIDRemoteModeExclusiveAuto))
+ {
+ if ((rootService = IORegistryEntryFromPath(_masterPort, kIOServicePlane ":/")) != 0)
+ {
+ kernReturn = IOServiceAddInterestNotification( _notifyPort,
+ rootService,
+ kIOBusyInterest,
+ SecureInputNotificationCallback,
+ (void *)self,
+ &_secureInputNotification);
+ if (kernReturn != kIOReturnSuccess) { break; }
+
+ [self _updateSessionInformation];
+ }
+ else
+ {
+ break;
+ }
+ }
// Setup notification matching dict
matchDict = IOServiceMatching(kIOHIDDeviceKey);
@@ -296,7 +328,7 @@ static HIDRemote *sHIDRemote = nil;
NSEnumerator *mapKeyEnum = [cloneDict keyEnumerator];
NSNumber *serviceValue;
- while (serviceValue = [mapKeyEnum nextObject])
+ while ((serviceValue = [mapKeyEnum nextObject]) != nil)
{
[self _destructService:(io_object_t)[serviceValue unsignedIntValue]];
};
@@ -314,6 +346,12 @@ static HIDRemote *sHIDRemote = nil;
IOObjectRelease((io_object_t) _matchingServicesIterator);
_matchingServicesIterator = 0;
}
+
+ if (_secureInputNotification)
+ {
+ IOObjectRelease((io_object_t) _secureInputNotification);
+ _secureInputNotification = 0;
+ }
if (_notifyRLSource)
{
@@ -333,12 +371,6 @@ static HIDRemote *sHIDRemote = nil;
mach_port_deallocate(mach_task_self(), _masterPort);
}
- if (_statusSecureEventInputWorkAroundEnabled)
- {
- DisableSecureEventInput();
- _statusSecureEventInputWorkAroundEnabled = NO;
- }
-
[self _postStatusWithAction:kHIDRemoteDNStatusActionStop];
[_returnToPID release];
@@ -362,6 +394,11 @@ static HIDRemote *sHIDRemote = nil;
return (_lastSeenRemoteID);
}
+- (HIDRemoteModel)lastSeenModel
+{
+ return (_lastSeenModel);
+}
+
- (void)setSimulateHoldEvents:(BOOL)newSimulateHoldEvents
{
_simulateHoldEvents = newSimulateHoldEvents;
@@ -401,25 +438,6 @@ static HIDRemote *sHIDRemote = nil;
- (void)setEnableSecureEventInputWorkaround:(BOOL)newEnableSecureEventInputWorkaround
{
_secureEventInputWorkAround = newEnableSecureEventInputWorkaround;
-
- if ([self isStarted])
- {
- if (_mode != kHIDRemoteModeShared)
- {
- // Changes go live immediately
- if (_secureEventInputWorkAround && !_statusSecureEventInputWorkAroundEnabled)
- {
- EnableSecureEventInput();
- _statusSecureEventInputWorkAroundEnabled = YES;
- }
-
- if (!_secureEventInputWorkAround && _statusSecureEventInputWorkAroundEnabled)
- {
- DisableSecureEventInput();
- _statusSecureEventInputWorkAroundEnabled = NO;
- }
- }
- }
}
- (BOOL)enableSecureEventInputWorkaround
@@ -663,16 +681,8 @@ static HIDRemote *sHIDRemote = nil;
if (_waitForReturnByPID != nil)
{
- BOOL cachedStatusSecureEventInputWorkAroundEnabled;
-
- // Workaround for what seems to be a missing lock on the counter in the EnableSecureEventInput() / DisableSecureEventInput() API
- cachedStatusSecureEventInputWorkAroundEnabled = _statusSecureEventInputWorkAroundEnabled;
- _statusSecureEventInputWorkAroundEnabled = NO;
-
[self stopRemoteControl];
- _statusSecureEventInputWorkAroundEnabled = cachedStatusSecureEventInputWorkAroundEnabled;
-
[[NSDistributedNotificationCenter defaultCenter] postNotificationName:kHIDRemoteDNHIDRemoteRetry
object:[NSString stringWithFormat:@"%d", [_waitForReturnByPID intValue]]
userInfo:[NSDictionary dictionaryWithObjectsAndKeys:
@@ -761,6 +771,101 @@ static HIDRemote *sHIDRemote = nil;
return (serviceMatches);
}
+- (HIDRemoteButtonCode)buttonCodeForUsage:(unsigned int)usage usagePage:(unsigned int)usagePage
+{
+ HIDRemoteButtonCode buttonCode = kHIDRemoteButtonCodeNone;
+
+ switch (usagePage)
+ {
+ case kHIDPage_Consumer:
+ switch (usage)
+ {
+ case kHIDUsage_Csmr_MenuPick:
+ // Aluminum Remote: Center
+ buttonCode = (kHIDRemoteButtonCodeCenter|kHIDRemoteButtonCodeAluminumMask);
+ break;
+
+ case kHIDUsage_Csmr_ModeStep:
+ // Aluminium Remote: Center Hold
+ buttonCode = (kHIDRemoteButtonCodeCenterHold|kHIDRemoteButtonCodeAluminumMask);
+ break;
+
+ case kHIDUsage_Csmr_PlayOrPause:
+ // Aluminum Remote: Play/Pause
+ buttonCode = (kHIDRemoteButtonCodePlay|kHIDRemoteButtonCodeAluminumMask);
+ break;
+
+ case kHIDUsage_Csmr_Rewind:
+ buttonCode = kHIDRemoteButtonCodeLeftHold;
+ break;
+
+ case kHIDUsage_Csmr_FastForward:
+ buttonCode = kHIDRemoteButtonCodeRightHold;
+ break;
+
+ case kHIDUsage_Csmr_Menu:
+ buttonCode = kHIDRemoteButtonCodeMenuHold;
+ break;
+ }
+ break;
+
+ case kHIDPage_GenericDesktop:
+ switch (usage)
+ {
+ case kHIDUsage_GD_SystemAppMenu:
+ buttonCode = kHIDRemoteButtonCodeMenu;
+ break;
+
+ case kHIDUsage_GD_SystemMenu:
+ buttonCode = kHIDRemoteButtonCodeCenter;
+ break;
+
+ case kHIDUsage_GD_SystemMenuRight:
+ buttonCode = kHIDRemoteButtonCodeRight;
+ break;
+
+ case kHIDUsage_GD_SystemMenuLeft:
+ buttonCode = kHIDRemoteButtonCodeLeft;
+ break;
+
+ case kHIDUsage_GD_SystemMenuUp:
+ buttonCode = kHIDRemoteButtonCodeUp;
+ break;
+
+ case kHIDUsage_GD_SystemMenuDown:
+ buttonCode = kHIDRemoteButtonCodeDown;
+ break;
+ }
+ break;
+
+ case 0x06: /* Reserved */
+ switch (usage)
+ {
+ case 0x22:
+ buttonCode = kHIDRemoteButtonCodeIDChanged;
+ break;
+ }
+ break;
+
+ case 0xFF01: /* Vendor specific */
+ switch (usage)
+ {
+ case 0x23:
+ buttonCode = kHIDRemoteButtonCodeCenterHold;
+ break;
+
+ #ifdef _HIDREMOTE_EXTENSIONS
+ #define _HIDREMOTE_EXTENSIONS_SECTION 2
+ #include "HIDRemoteAdditions.h"
+ #undef _HIDREMOTE_EXTENSIONS_SECTION
+ #endif /* _HIDREMOTE_EXTENSIONS */
+ }
+ break;
+ }
+
+ return (buttonCode);
+}
+
- (BOOL)_setupService:(io_object_t)service
{
kern_return_t kernResult;
@@ -913,78 +1018,14 @@ static HIDRemote *sHIDRemote = nil;
if (usage && usagePage && cookie)
{
// Find the button codes for the ID combos
- switch ([usagePage unsignedIntValue])
- {
- case kHIDPage_Consumer:
- switch ([usage unsignedIntValue])
- {
- case kHIDUsage_Csmr_Rewind:
- buttonCode = kHIDRemoteButtonCodeLeftHold;
- break;
-
- case kHIDUsage_Csmr_FastForward:
- buttonCode = kHIDRemoteButtonCodeRightHold;
- break;
-
- case kHIDUsage_Csmr_Menu:
- buttonCode = kHIDRemoteButtonCodeMenuHold;
- break;
- }
- break;
-
- case kHIDPage_GenericDesktop:
- switch ([usage unsignedIntValue])
- {
- case kHIDUsage_GD_SystemAppMenu:
- buttonCode = kHIDRemoteButtonCodeMenu;
- break;
-
- case kHIDUsage_GD_SystemMenu:
- buttonCode = kHIDRemoteButtonCodePlayPause;
- break;
-
- case kHIDUsage_GD_SystemMenuRight:
- buttonCode = kHIDRemoteButtonCodeRight;
- break;
-
- case kHIDUsage_GD_SystemMenuLeft:
- buttonCode = kHIDRemoteButtonCodeLeft;
- break;
-
- case kHIDUsage_GD_SystemMenuUp:
- buttonCode = kHIDRemoteButtonCodePlus;
- break;
-
- case kHIDUsage_GD_SystemMenuDown:
- buttonCode = kHIDRemoteButtonCodeMinus;
- break;
- }
- break;
-
- case 0x06: /* Resered */
- switch ([usage unsignedIntValue])
- {
- case 0x22:
- buttonCode = kHIDRemoteButtonCodeIDChanged;
- break;
- }
- break;
-
- case 0xff01: /* Vendor specific */
- switch ([usage unsignedIntValue])
- {
- case 0x23:
- buttonCode = kHIDRemoteButtonCodePlayPauseHold;
- break;
-
- #ifdef _HIDREMOTE_EXTENSIONS
- #define _HIDREMOTE_EXTENSIONS_SECTION 2
- #include "HIDRemoteAdditions.h"
- #undef _HIDREMOTE_EXTENSIONS_SECTION
- #endif /* _HIDREMOTE_EXTENSIONS */
- }
- break;
- }
+ buttonCode = [self buttonCodeForUsage:[usage unsignedIntValue] usagePage:[usagePage unsignedIntValue]];
+
+ #ifdef _HIDREMOTE_EXTENSIONS
+ // Debug logging code
+ #define _HIDREMOTE_EXTENSIONS_SECTION 3
+ #include "HIDRemoteAdditions.h"
+ #undef _HIDREMOTE_EXTENSIONS_SECTION
+ #endif /* _HIDREMOTE_EXTENSIONS */
// Did record match?
if (buttonCode != kHIDRemoteButtonCodeNone)
@@ -992,6 +1033,13 @@ static HIDRemote *sHIDRemote = nil;
NSString *pairString = [[NSString alloc] initWithFormat:@"%u_%u", [usagePage unsignedIntValue], [usage unsignedIntValue]];
NSNumber *buttonCodeNumber = [[NSNumber alloc] initWithUnsignedInt:(unsigned int)buttonCode];
+ #ifdef _HIDREMOTE_EXTENSIONS
+ // Debug logging code
+ #define _HIDREMOTE_EXTENSIONS_SECTION 4
+ #include "HIDRemoteAdditions.h"
+ #undef _HIDREMOTE_EXTENSIONS_SECTION
+ #endif /* _HIDREMOTE_EXTENSIONS */
+
[cookieCount setObject:buttonCodeNumber forKey:pairString];
[cookieButtonCodeLUT setObject:buttonCodeNumber forKey:cookie];
@@ -1131,6 +1179,91 @@ static HIDRemote *sHIDRemote = nil;
}
}
+ // Determine Aluminum Remote support
+ {
+ CFNumberRef aluSupport;
+ HIDRemoteAluminumRemoteSupportLevel supportLevel = kHIDRemoteAluminumRemoteSupportLevelNone;
+
+ if ((_mode == kHIDRemoteModeExclusive) || (_mode == kHIDRemoteModeExclusiveAuto))
+ {
+ // Determine if this driver offers on-demand support for the Aluminum Remote (only relevant under OS versions < 10.6.2)
+ if ((aluSupport = IORegistryEntryCreateCFProperty((io_registry_entry_t)service,
+ (CFStringRef) @"AluminumRemoteSupportLevelOnDemand",
+ kCFAllocatorDefault,
+ 0)) != nil)
+ {
+ // There is => request the driver to enable it for us
+ if (IORegistryEntrySetCFProperty((io_registry_entry_t)service,
+ CFSTR("EnableAluminumRemoteSupportForMe"),
+ [NSDictionary dictionaryWithObjectsAndKeys:
+ [NSNumber numberWithLongLong:(long long)getpid()], @"pid",
+ [NSNumber numberWithLongLong:(long long)getuid()], @"uid",
+ nil]) == kIOReturnSuccess)
+ {
+ if (CFGetTypeID(aluSupport) == CFNumberGetTypeID())
+ {
+ supportLevel = (HIDRemoteAluminumRemoteSupportLevel) [(NSNumber *)aluSupport intValue];
+ }
+
+ [hidAttribsDict setObject:[NSNumber numberWithBool:YES] forKey:kHIDRemoteAluminumRemoteSupportOnDemand];
+ }
+
+ CFRelease(aluSupport);
+ }
+ }
+
+ if (supportLevel == kHIDRemoteAluminumRemoteSupportLevelNone)
+ {
+ if ((aluSupport = IORegistryEntryCreateCFProperty((io_registry_entry_t)service,
+ (CFStringRef) @"AluminumRemoteSupportLevel",
+ kCFAllocatorDefault,
+ 0)) != nil)
+ {
+ if (CFGetTypeID(aluSupport) == CFNumberGetTypeID())
+ {
+ supportLevel = (HIDRemoteAluminumRemoteSupportLevel) [(NSNumber *)aluSupport intValue];
+ }
+
+ CFRelease(aluSupport);
+ }
+ else
+ {
+ CFStringRef ioKitClassName;
+
+ if ((ioKitClassName = IORegistryEntryCreateCFProperty( (io_registry_entry_t)service,
+ CFSTR(kIOClassKey),
+ kCFAllocatorDefault,
+ 0)) != nil)
+ {
+ if ([(NSString *)ioKitClassName isEqual:@"AppleIRController"])
+ {
+ SInt32 systemVersion;
+
+ if (Gestalt(gestaltSystemVersion, &systemVersion) == noErr)
+ {
+ if (systemVersion >= 0x1062)
+ {
+ // Support for the Aluminum Remote was added only with OS 10.6.2. Previous versions can not distinguish
+ // between the Center and the new, seperate Play/Pause button. They'll recognize both as presses of the
+ // "Center" button.
+ //
+ // You CAN, however, receive Aluminum Remote button presses even under OS 10.5 when using Remote Buddy's
+ // Virtual Remote. While Remote Buddy does support the Aluminum Remote across all OS releases it runs on,
+ // its Virtual Remote can only emulate Aluminum Remote button presses under OS 10.5 and up in order not to
+ // break compatibility with applications whose IR Remote code relies on driver internals. [13-Nov-09]
+ supportLevel = kHIDRemoteAluminumRemoteSupportLevelNative;
+ }
+ }
+ }
+
+ CFRelease(ioKitClassName);
+ }
+ }
+ }
+
+ [hidAttribsDict setObject:(NSNumber *)[NSNumber numberWithInt:(int)supportLevel] forKey:kHIDRemoteAluminumRemoteSupportLevel];
+ }
+
// Add it to the serviceAttribMap
[_serviceAttribMap setObject:hidAttribsDict forKey:[NSNumber numberWithUnsignedInt:(unsigned int)service]];
@@ -1255,6 +1388,17 @@ static HIDRemote *sHIDRemote = nil;
[serviceDict retain];
[_serviceAttribMap removeObjectForKey:serviceValue];
+ if (([serviceDict objectForKey:kHIDRemoteAluminumRemoteSupportOnDemand]!=nil) && [[serviceDict objectForKey:kHIDRemoteAluminumRemoteSupportOnDemand] boolValue] && (theService != 0))
+ {
+ // 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]);
+ }
+
if (([self delegate]!=nil) &&
([[self delegate] respondsToSelector:@selector(hidRemote:releasedHardwareWithAttributes:)]))
{
@@ -1283,7 +1427,7 @@ static HIDRemote *sHIDRemote = nil;
NSEnumerator *cookieEnum = [cookieButtonMap keyEnumerator];
NSNumber *cookie;
- while (cookie = [cookieEnum nextObject])
+ while ((cookie = [cookieEnum nextObject]) != nil)
{
if ((*hidQueueInterface)->hasElement(hidQueueInterface, (IOHIDElementCookie) [cookie unsignedIntValue]))
{
@@ -1349,8 +1493,8 @@ static HIDRemote *sHIDRemote = nil;
// Do nothing, this is handled seperately
break;
- case kHIDRemoteButtonCodePlus:
- case kHIDRemoteButtonCodeMinus:
+ case kHIDRemoteButtonCodeUp:
+ case kHIDRemoteButtonCodeDown:
if (_simulateHoldEvents)
{
NSTimer *shTimer = nil;
@@ -1412,7 +1556,38 @@ static HIDRemote *sHIDRemote = nil;
if (([self delegate]!=nil) &&
([[self delegate] respondsToSelector:@selector(hidRemote:eventWithButton:isPressed:fromHardwareWithAttributes:)]))
{
- [((NSObject <HIDRemoteDelegate> *)[self delegate]) hidRemote:self eventWithButton:buttonCode isPressed:isPressed fromHardwareWithAttributes:hidAttribsDict];
+ switch (buttonCode & (~kHIDRemoteButtonCodeAluminumMask))
+ {
+ case kHIDRemoteButtonCodePlay:
+ case kHIDRemoteButtonCodeCenter:
+ if (buttonCode & kHIDRemoteButtonCodeAluminumMask)
+ {
+ _lastSeenModel = kHIDRemoteModelAluminum;
+ _lastSeenModelRemoteID = _lastSeenRemoteID;
+ }
+ else
+ {
+ switch ((HIDRemoteAluminumRemoteSupportLevel)[[hidAttribsDict objectForKey:kHIDRemoteAluminumRemoteSupportLevel] intValue])
+ {
+ case kHIDRemoteAluminumRemoteSupportLevelNone:
+ case kHIDRemoteAluminumRemoteSupportLevelEmulation:
+ // Remote type can't be determined by just the Center button press
+ break;
+
+ case kHIDRemoteAluminumRemoteSupportLevelNative:
+ // Remote type can be safely determined by just the Center button press
+ if (((_lastSeenModel == kHIDRemoteModelAluminum) && (_lastSeenModelRemoteID != _lastSeenRemoteID)) ||
+ (_lastSeenModel == kHIDRemoteModelUndetermined))
+ {
+ _lastSeenModel = kHIDRemoteModelWhitePlastic;
+ }
+ break;
+ }
+ }
+ break;
+ }
+
+ [((NSObject <HIDRemoteDelegate> *)[self delegate]) hidRemote:self eventWithButton:(buttonCode & (~kHIDRemoteButtonCodeAluminumMask)) isPressed:isPressed fromHardwareWithAttributes:hidAttribsDict];
}
}
@@ -1453,6 +1628,13 @@ static HIDRemote *sHIDRemote = nil;
{
NSNumber *buttonCodeNumber = [cookieButtonMap objectForKey:[NSNumber numberWithUnsignedInt:(unsigned int) hidEvent.elementCookie]];
+ #ifdef _HIDREMOTE_EXTENSIONS
+ // Debug logging code
+ #define _HIDREMOTE_EXTENSIONS_SECTION 5
+ #include "HIDRemoteAdditions.h"
+ #undef _HIDREMOTE_EXTENSIONS_SECTION
+ #endif /* _HIDREMOTE_EXTENSIONS */
+
if (buttonCodeNumber)
{
HIDRemoteButtonCode buttonCode = [buttonCodeNumber unsignedIntValue];
@@ -1483,6 +1665,7 @@ static HIDRemote *sHIDRemote = nil;
}
_lastSeenRemoteID = hidEvent.value;
+ _lastSeenModel = kHIDRemoteModelUndetermined;
}
[self _handleButtonCode:buttonCode isPressed:YES hidAttribsDict:hidAttribsDict];
@@ -1494,6 +1677,13 @@ static HIDRemote *sHIDRemote = nil;
[hidAttribsDict setObject:[NSNumber numberWithUnsignedInt:lastButtonPressed] forKey:kHIDRemoteLastButtonPressed];
}
+
+ #ifdef _HIDREMOTE_EXTENSIONS
+ // Debug logging code
+ #define _HIDREMOTE_EXTENSIONS_SECTION 6
+ #include "HIDRemoteAdditions.h"
+ #undef _HIDREMOTE_EXTENSIONS_SECTION
+ #endif /* _HIDREMOTE_EXTENSIONS */
}
}
@@ -1502,7 +1692,7 @@ static HIDRemote *sHIDRemote = nil;
{
io_object_t matchingService = 0;
- while (matchingService = IOIteratorNext(iterator))
+ while ((matchingService = IOIteratorNext(iterator)) != 0)
{
[self _setupService:matchingService];
@@ -1518,6 +1708,89 @@ static HIDRemote *sHIDRemote = nil;
}
}
+- (void)_updateSessionInformation
+{
+ NSArray *consoleUsersArray;
+ io_service_t rootService;
+
+ if ((rootService = IORegistryGetRootEntry(_masterPort)) != 0)
+ {
+ if ((consoleUsersArray = (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
+ {
+ NSEnumerator *consoleUsersEnum; // I *love* Obj-C2's fast enumerators, but we need to stay compatible with 10.4 :-/
+
+ if ((consoleUsersEnum = [consoleUsersArray objectEnumerator]) != nil)
+ {
+ UInt64 secureEventInputPIDSum = 0;
+ uid_t frontUserSession = 0;
+ NSDictionary *consoleUserDict;
+
+ while ((consoleUserDict = [consoleUsersEnum nextObject]) != nil)
+ {
+ if ([consoleUserDict isKindOfClass:[NSDictionary class]]) // Be careful - ensure this really is a dictionary
+ {
+ NSNumber *secureInputPID;
+ NSNumber *onConsole;
+ NSNumber *userID;
+
+ if ((secureInputPID = [consoleUserDict objectForKey:@"kCGSSessionSecureInputPID"]) != nil)
+ {
+ if ([secureInputPID isKindOfClass:[NSNumber class]])
+ {
+ secureEventInputPIDSum += ((UInt64) [secureInputPID intValue]);
+ }
+ }
+
+ if (((onConsole = [consoleUserDict objectForKey:@"kCGSSessionOnConsoleKey"]) != nil) &&
+ ((userID = [consoleUserDict objectForKey:@"kCGSSessionUserIDKey"]) != nil))
+ {
+ if ([onConsole isKindOfClass:[NSNumber class]] && [userID isKindOfClass:[NSNumber class]])
+ {
+ if ([onConsole boolValue])
+ {
+ frontUserSession = (uid_t) [userID intValue];
+ }
+ }
+ }
+ }
+ }
+
+ _lastSecureEventInputPIDSum = secureEventInputPIDSum;
+ _lastFrontUserSession = frontUserSession;
+ }
+ }
+
+ CFRelease((CFTypeRef)consoleUsersArray);
+ }
+
+ IOObjectRelease((io_object_t) rootService);
+ }
+}
+
+- (void)_secureInputNotificationFor:(io_service_t)service messageType:(natural_t)messageType messageArgument:(void *)messageArgument
+{
+ if (messageType == kIOMessageServiceBusyStateChange)
+ {
+ UInt64 old_lastSecureEventInputPIDSum = _lastSecureEventInputPIDSum;
+ uid_t old_lastFrontUserSession = _lastFrontUserSession;
+
+ [self _updateSessionInformation];
+
+ if (((old_lastSecureEventInputPIDSum != _lastSecureEventInputPIDSum) || (old_lastFrontUserSession != _lastFrontUserSession)) && _secureEventInputWorkAround)
+ {
+ if ((_mode == kHIDRemoteModeExclusive) || (_mode == kHIDRemoteModeExclusiveAuto))
+ {
+ HIDRemoteMode restartInMode = _mode;
+
+ [self stopRemoteControl];
+ [self startRemoteControl:restartInMode];
+ }
+ }
+ }
+}
+
@end
#pragma mark -- PRIVATE: IOKitLib Callbacks --
@@ -1562,6 +1835,21 @@ static void ServiceNotificationCallback(void * refCon,
[pool release];
}
+static void SecureInputNotificationCallback( void * refCon,
+ io_service_t service,
+ natural_t messageType,
+ void * messageArgument)
+{
+ HIDRemote *hidRemote = (HIDRemote *)refCon;
+ NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
+
+ [hidRemote _secureInputNotificationFor:service
+ messageType:messageType
+ messageArgument:messageArgument];
+
+ [pool release];
+}
+
// Attribute dictionary keys
NSString *kHIDRemoteCFPluginInterface = @"CFPluginInterface";
NSString *kHIDRemoteHIDDeviceInterface = @"HIDDeviceInterface";
@@ -1573,6 +1861,8 @@ NSString *kHIDRemoteLastButtonPressed = @"LastButtonPressed";
NSString *kHIDRemoteService = @"Service";
NSString *kHIDRemoteSimulateHoldEventsTimer = @"SimulateHoldEventsTimer";
NSString *kHIDRemoteSimulateHoldEventsOriginButtonCode = @"SimulateHoldEventsOriginButtonCode";
+NSString *kHIDRemoteAluminumRemoteSupportLevel = @"AluminumRemoteSupportLevel";
+NSString *kHIDRemoteAluminumRemoteSupportOnDemand = @"AluminumRemoteSupportLevelOnDemand";
NSString *kHIDRemoteManufacturer = @"Manufacturer";
NSString *kHIDRemoteProduct = @"Product";