Commit da380a41 authored by Felix Paul Kühne's avatar Felix Paul Kühne

macosx: updated cookie for the 2009 Apple Remote and fixed a minor issue when...

macosx: updated cookie for the 2009 Apple Remote and fixed a minor issue when switching between multiple remotes
parent 302e7eb5
......@@ -32,7 +32,7 @@
* or (at your option) any later version.
* Thus, the following statements apply to our changes:
*
* Copyright (C) 2006-2007 the VideoLAN team
* Copyright (C) 2006-2011 the VideoLAN team
* Authors: Eric Petit <titer@m0k.org>
* Felix Kühne <fkuehne at videolan dot org>
*
......@@ -74,38 +74,40 @@ enum AppleRemoteEventIdentifier
kRemoteControl_Switched =1<<11,
kRemoteButtonVolume_Plus_Hold =1<<12,
kRemoteButtonVolume_Minus_Hold =1<<13,
k2009RemoteButtonPlay =1<<14,
k2009RemoteButtonFullscreen =1<<15
k2009RemoteButtonPlay =1<<14,
k2009RemoteButtonFullscreen =1<<15,
k2009RemoteButtonSwitched =1<<16
};
typedef enum AppleRemoteEventIdentifier AppleRemoteEventIdentifier;
/* Encapsulates usage of the apple remote control
This class is implemented as a singleton as there is exactly one remote per machine (until now)
The class is not thread safe
*/
This class is implemented as a singleton as there is exactly one remote per machine (until now)
The class is not thread safe
*/
@interface AppleRemote : NSObject {
IOHIDDeviceInterface** hidDeviceInterface;
IOHIDQueueInterface** queue;
NSMutableArray* allCookies;
NSMutableDictionary* cookieToButtonMapping;
NSString* switchCookie;
CFRunLoopSourceRef eventSource;
BOOL openInExclusiveMode;
BOOL simulatePlusMinusHold;
BOOL processesBacklog;
/* state for simulating plus/minus hold */
BOOL lastEventSimulatedHold;
AppleRemoteEventIdentifier lastPlusMinusEvent;
NSTimeInterval lastPlusMinusEventTime;
int remoteId;
unsigned int clickCountEnabledButtons;
NSTimeInterval maxClickTimeDifference;
NSTimeInterval lastClickCountEventTime;
AppleRemoteEventIdentifier lastClickCountEvent;
unsigned int eventClickCount;
IBOutlet id delegate;
}
......@@ -178,6 +180,7 @@ The class is not thread safe
@interface AppleRemote (PrivateMethods)
- (void) setRemoteId: (int) aValue;
- (NSDictionary*) cookieToButtonMapping;
- (NSString *) switchCookie;
- (IOHIDQueueInterface**) queue;
- (IOHIDDeviceInterface**) hidDeviceInterface;
- (void) handleEventWithCookieString: (NSString*) cookieString sumOfValues: (SInt32) sumOfValues;
......
......@@ -32,7 +32,7 @@
* or (at your option) any later version.
* Thus, the following statements apply to our changes:
*
* Copyright (C) 2006-2009 the VideoLAN team
* Copyright (C) 2006-2011 the VideoLAN team
* Authors: Eric Petit <titer@m0k.org>
* Felix Kühne <fkuehne at videolan dot org>
*
......@@ -58,6 +58,7 @@
const char* AppleRemoteDeviceName = "AppleIRController";
const int REMOTE_SWITCH_COOKIE=19;
const int FUTURE_REMOTE_SWITCH_COOKIE=42;
const NSTimeInterval DEFAULT_MAXIMUM_CLICK_TIME_DIFFERENCE=0.35;
const NSTimeInterval HOLD_RECOGNITION_TIME_INTERVAL=0.4;
......@@ -71,7 +72,7 @@ const NSTimeInterval HOLD_RECOGNITION_TIME_INTERVAL=0.4;
queue = NULL;
hidDeviceInterface = NULL;
cookieToButtonMapping = [[NSMutableDictionary alloc] init];
if( NSAppKitVersionNumber < 1038.13 )
{
/* Leopard and early Snow Leopard Cookies */
......@@ -87,6 +88,7 @@ const NSTimeInterval HOLD_RECOGNITION_TIME_INTERVAL=0.4;
[cookieToButtonMapping setObject:[NSNumber numberWithInt:kRemoteButtonMenu_Hold] forKey:@"31_18_31_18_"];
[cookieToButtonMapping setObject:[NSNumber numberWithInt:kRemoteButtonPlay_Sleep] forKey:@"35_31_18_35_31_18_"];
[cookieToButtonMapping setObject:[NSNumber numberWithInt:kRemoteControl_Switched] forKey:@"19_"];
switchCookie = @"19_";
}
else if( NSAppKitVersionNumber >= 1115.2 )
{
......@@ -103,8 +105,10 @@ const NSTimeInterval HOLD_RECOGNITION_TIME_INTERVAL=0.4;
[cookieToButtonMapping setObject:[NSNumber numberWithInt:kRemoteButtonMenu_Hold] forKey:@"33_21_20_2_33_21_20_2_"];
[cookieToButtonMapping setObject:[NSNumber numberWithInt:kRemoteButtonPlay_Sleep] forKey:@"37_33_21_20_2_37_33_21_20_2_"];
[cookieToButtonMapping setObject:[NSNumber numberWithInt:kRemoteControl_Switched] forKey:@"42_33_23_21_20_2_33_23_21_20_2_"];
[cookieToButtonMapping setObject:[NSNumber numberWithInt:k2009RemoteButtonSwitched] forKey:@"42_33_21_20_8_2_33_21_20_8_2_"];
[cookieToButtonMapping setObject:[NSNumber numberWithInt:k2009RemoteButtonPlay] forKey:@"33_21_20_8_2_33_21_20_8_2_"];
[cookieToButtonMapping setObject:[NSNumber numberWithInt:k2009RemoteButtonFullscreen] forKey:@"33_21_20_3_2_33_21_20_3_2_"];
[cookieToButtonMapping setObject:[NSNumber numberWithInt:k2009RemoteButtonFullscreen] forKey:@"33_21_20_3_2_33_21_20_3_2_"];
switchCookie = @"42_33_23_21_20_2_33_23_21_20_2_";
}
else
{
......@@ -123,19 +127,21 @@ const NSTimeInterval HOLD_RECOGNITION_TIME_INTERVAL=0.4;
[cookieToButtonMapping setObject:[NSNumber numberWithInt:kRemoteControl_Switched] forKey:@"19_"];
[cookieToButtonMapping setObject:[NSNumber numberWithInt:k2009RemoteButtonPlay] forKey:@"33_21_20_8_2_33_21_20_8_2_"];
[cookieToButtonMapping setObject:[NSNumber numberWithInt:k2009RemoteButtonFullscreen] forKey:@"33_21_20_3_2_33_21_20_3_2_"];
switchCookie = @"19_";
}
}
/* defaults */
[self setSimulatesPlusMinusHold: YES];
maxClickTimeDifference = DEFAULT_MAXIMUM_CLICK_TIME_DIFFERENCE;
return self;
}
- (void) dealloc {
[self stopListening:self];
[cookieToButtonMapping release];
[switchCookie release];
[super dealloc];
}
......@@ -172,7 +178,7 @@ const NSTimeInterval HOLD_RECOGNITION_TIME_INTERVAL=0.4;
* to receive delegation messages. To do this, they may have to retain the delegate. */
- (void) setDelegate: (id) _delegate {
if (_delegate && [_delegate respondsToSelector:@selector(appleRemoteButton:pressedDown:clickCount:)]==NO) return;
delegate = _delegate;
}
- (id) delegate {
......@@ -246,26 +252,26 @@ const NSTimeInterval HOLD_RECOGNITION_TIME_INTERVAL=0.4;
- (IBAction) startListening: (id) sender {
if ([self isListeningToRemote]) return;
io_object_t hidDevice = [self findAppleRemoteDevice];
if (hidDevice == 0) return;
if ([self createInterfaceForDevice:hidDevice] == NULL) {
goto error;
}
if ([self initializeCookies]==NO) {
goto error;
}
if ([self openDevice]==NO) {
goto error;
}
goto cleanup;
error:
[self stopListening:self];
cleanup:
IOObjectRelease(hidDevice);
}
......@@ -278,28 +284,28 @@ cleanup:
}
if (queue != NULL) {
(*queue)->stop(queue);
//dispose of queue
(*queue)->dispose(queue);
//release the queue we allocated
(*queue)->Release(queue);
queue = NULL;
}
if (allCookies != nil) {
[allCookies autorelease];
allCookies = nil;
}
if (hidDeviceInterface != NULL) {
//close the device
(*hidDeviceInterface)->close(hidDeviceInterface);
//release the interface
(*hidDeviceInterface)->Release(hidDeviceInterface);
hidDeviceInterface = NULL;
}
}
......@@ -358,6 +364,9 @@ static AppleRemote* sharedInstance=nil;
return hidDeviceInterface;
}
- (NSString *) switchCookie {
return switchCookie;
}
- (NSDictionary*) cookieToButtonMapping {
return cookieToButtonMapping;
......@@ -412,7 +421,7 @@ static AppleRemote* sharedInstance=nil;
}
}
}
if (([self clickCountEnabledButtons] & event) == event) {
if (pressedDown==NO && (event == kRemoteButtonVolume_Minus || event == kRemoteButtonVolume_Plus)) {
return; // this one is triggered automatically by the handler
......@@ -442,15 +451,15 @@ static AppleRemote* sharedInstance=nil;
- (void) executeClickCountEvent: (NSArray*) values {
AppleRemoteEventIdentifier event = [[values objectAtIndex: 0] unsignedIntValue];
NSTimeInterval eventTimePoint = [[values objectAtIndex: 1] doubleValue];
BOOL finishedClicking = NO;
int finalClickCount = eventClickCount;
@synchronized(self) {
finishedClicking = (event != lastClickCountEvent || eventTimePoint == lastClickCountEventTime);
if (finishedClicking) eventClickCount = 0;
}
if (finishedClicking) {
[delegate appleRemoteButton:event pressedDown: YES clickCount:finalClickCount];
if ([self simulatesPlusMinusHold]==NO && (event == kRemoteButtonVolume_Minus || event == kRemoteButtonVolume_Plus)) {
......@@ -459,16 +468,16 @@ static AppleRemote* sharedInstance=nil;
[delegate appleRemoteButton:event pressedDown: NO clickCount:finalClickCount];
}
}
}
- (void) handleEventWithCookieString: (NSString*) cookieString sumOfValues: (SInt32) sumOfValues {
/*
if (previousRemainingCookieString) {
cookieString = [previousRemainingCookieString stringByAppendingString: cookieString];
NSLog(@"New cookie string is %@", cookieString);
[previousRemainingCookieString release], previousRemainingCookieString=nil;
}*/
if (previousRemainingCookieString) {
cookieString = [previousRemainingCookieString stringByAppendingString: cookieString];
NSLog(@"New cookie string is %@", cookieString);
[previousRemainingCookieString release], previousRemainingCookieString=nil;
}*/
if (cookieString == nil || [cookieString length] == 0) return;
NSNumber* buttonId = [[self cookieToButtonMapping] objectForKey: cookieString];
if (buttonId != nil) {
......@@ -499,11 +508,11 @@ static AppleRemote* sharedInstance=nil;
@end
/* Callback method for the device queue
Will be called for any event of any type (cookie) to which we subscribe
*/
Will be called for any event of any type (cookie) to which we subscribe
*/
static void QueueCallbackFunction(void* target, IOReturn result, void* refcon, void* sender) {
AppleRemote* remote = (AppleRemote*)target;
IOHIDEventStruct event;
AbsoluteTime zeroTime = {0,0};
NSMutableString* cookieString = [NSMutableString string];
......@@ -513,12 +522,12 @@ static void QueueCallbackFunction(void* target, IOReturn result, void* refcon,
result = (*[remote queue])->getNextEvent([remote queue], &event, zeroTime, 0);
if ( result != kIOReturnSuccess )
continue;
//printf("%d %d %d\n", event.elementCookie, event.value, event.longValue);
if (REMOTE_SWITCH_COOKIE == (int)event.elementCookie) {
if (REMOTE_SWITCH_COOKIE == (int)event.elementCookie || FUTURE_REMOTE_SWITCH_COOKIE == (int)event.elementCookie) {
[remote setRemoteId: event.value];
[remote handleEventWithCookieString: @"19_" sumOfValues: 0];
[remote handleEventWithCookieString: [remote switchCookie] sumOfValues: 0];
} else {
if (((int)event.elementCookie)!=5) {
sumOfValues+=event.value;
......@@ -526,7 +535,7 @@ static void QueueCallbackFunction(void* target, IOReturn result, void* refcon,
}
}
}
[remote handleEventWithCookieString: cookieString sumOfValues: sumOfValues];
}
......@@ -538,16 +547,16 @@ static void QueueCallbackFunction(void* target, IOReturn result, void* refcon,
HRESULT plugInResult = S_OK;
SInt32 score = 0;
IOReturn ioReturnValue = kIOReturnSuccess;
hidDeviceInterface = NULL;
ioReturnValue = IOObjectGetClass(hidDevice, className);
if (ioReturnValue != kIOReturnSuccess) {
msg_Err( VLCIntf, "Failed to get IOKit class name.");
return NULL;
}
ioReturnValue = IOCreatePlugInInterfaceForService(hidDevice,
kIOHIDDeviceUserClientTypeID,
kIOCFPlugInInterfaceID,
......@@ -557,7 +566,7 @@ static void QueueCallbackFunction(void* target, IOReturn result, void* refcon,
{
//Call a method of the intermediate plug-in to create the device interface
plugInResult = (*plugInInterface)->QueryInterface(plugInInterface, CFUUIDGetUUIDBytes(kIOHIDDeviceInterfaceID), (LPVOID) &hidDeviceInterface);
if (plugInResult != S_OK) {
msg_Err( VLCIntf, "Couldn't create HID class device interface");
}
......@@ -572,21 +581,21 @@ static void QueueCallbackFunction(void* target, IOReturn result, void* refcon,
IOReturn ioReturnValue = kIOReturnSuccess;
io_iterator_t hidObjectIterator = 0;
io_object_t hidDevice = 0;
// Set up a matching dictionary to search the I/O Registry by class
// name for all HID class devices
hidMatchDictionary = IOServiceMatching(AppleRemoteDeviceName);
// Now search I/O Registry for matching devices.
ioReturnValue = IOServiceGetMatchingServices(kIOMasterPortDefault, hidMatchDictionary, &hidObjectIterator);
if ((ioReturnValue == kIOReturnSuccess) && (hidObjectIterator != 0)) {
hidDevice = IOIteratorNext(hidObjectIterator);
}
// release the iterator
IOObjectRelease(hidObjectIterator);
return hidDevice;
}
......@@ -599,70 +608,70 @@ static void QueueCallbackFunction(void* target, IOReturn result, void* refcon,
NSArray* elements = nil;
NSDictionary* element;
IOReturn success;
if (!handle || !(*handle)) return NO;
/* Copy all elements, since we're grabbing most of the elements
* for this device anyway, and thus, it's faster to iterate them
* ourselves. When grabbing only one or two elements, a matching
* dictionary should be passed in here instead of NULL. */
success = (*handle)->copyMatchingElements(handle, NULL, (CFArrayRef*)&elements);
if (success == kIOReturnSuccess) {
[elements autorelease];
/*
cookies = calloc(NUMBER_OF_APPLE_REMOTE_ACTIONS, sizeof(IOHIDElementCookie));
memset(cookies, 0, sizeof(IOHIDElementCookie) * NUMBER_OF_APPLE_REMOTE_ACTIONS);
*/
cookies = calloc(NUMBER_OF_APPLE_REMOTE_ACTIONS, sizeof(IOHIDElementCookie));
memset(cookies, 0, sizeof(IOHIDElementCookie) * NUMBER_OF_APPLE_REMOTE_ACTIONS);
*/
allCookies = [[NSMutableArray alloc] init];
unsigned int i;
for (i=0; i< [elements count]; i++) {
element = [elements objectAtIndex:i];
//Get cookie
object = [element valueForKey: (NSString*)CFSTR(kIOHIDElementCookieKey) ];
if (object == nil || ![object isKindOfClass:[NSNumber class]]) continue;
if (object == 0 || CFGetTypeID(object) != CFNumberGetTypeID()) continue;
cookie = (IOHIDElementCookie) [object longValue];
//Get usage
object = [element valueForKey: (NSString*)CFSTR(kIOHIDElementUsageKey) ];
if (object == nil || ![object isKindOfClass:[NSNumber class]]) continue;
usage = [object longValue];
//Get usage page
object = [element valueForKey: (NSString*)CFSTR(kIOHIDElementUsagePageKey) ];
if (object == nil || ![object isKindOfClass:[NSNumber class]]) continue;
usagePage = [object longValue];
[allCookies addObject: [NSNumber numberWithInt:(int)cookie]];
}
} else {
return NO;
}
return YES;
}
- (BOOL) openDevice {
HRESULT result;
IOHIDOptionsType openMode = kIOHIDOptionsTypeNone;
if ([self isOpenInExclusiveMode]) openMode = kIOHIDOptionsTypeSeizeDevice;
IOReturn ioReturnValue = (*hidDeviceInterface)->open(hidDeviceInterface, openMode);
if (ioReturnValue == KERN_SUCCESS) {
queue = (*hidDeviceInterface)->allocQueue(hidDeviceInterface);
if (queue) {
result = (*queue)->create(queue, 0, 12); //depth: maximum number of elements in queue before oldest elements in queue begin to be lost.
unsigned int i=0;
for(i=0; i<[allCookies count]; i++) {
IOHIDElementCookie cookie = (IOHIDElementCookie)[[allCookies objectAtIndex:i] intValue];
(*queue)->addElement(queue, cookie, 0);
}
// add callback for async events
ioReturnValue = (*queue)->createAsyncEventSource(queue, &eventSource);
if (ioReturnValue == KERN_SUCCESS) {
......@@ -711,14 +720,14 @@ static void QueueCallbackFunction(void* target, IOReturn result, void* refcon,
}
- (void)applicationDidBecomeActive:(NSNotification *)aNotification {
[[AppleRemote sharedRemote] setListeningToRemote: YES];
if ([applicationDelegate respondsToSelector: @selector(applicationDidBecomeActive:)]) {
[applicationDelegate applicationDidBecomeActive: aNotification];
}
}
- (void)applicationWillResignActive:(NSNotification *)aNotification {
[[AppleRemote sharedRemote] setListeningToRemote: NO];
if ([applicationDelegate respondsToSelector: @selector(applicationWillResignActive:)]) {
[applicationDelegate applicationWillResignActive: aNotification];
}
......@@ -739,12 +748,12 @@ static void QueueCallbackFunction(void* target, IOReturn result, void* refcon,
- (void)forwardInvocation:(NSInvocation *)invocation {
SEL aSelector = [invocation selector];
if (applicationDelegate==nil || [applicationDelegate respondsToSelector:aSelector]==NO) {
[super forwardInvocation: invocation];
return;
}
[invocation invokeWithTarget:applicationDelegate];
}
@end
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment