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

* modernise the Apple Remote architecture by back-porting an adapted trunk...

* modernise the Apple Remote architecture by back-porting an adapted trunk version. This fixes the AR support on Tiger and provides a couple of new features (skipping, better volume control, easy to find fullscreen-mode-toggle). additionally, fixed a nasty bug which prevented proper toggling of the fullscreen mode.
parent 9f677d3a
...@@ -27,12 +27,12 @@ ...@@ -27,12 +27,12 @@
***************************************************************************** *****************************************************************************
* *
* Note that changes made by any members or contributors of the VideoLAN team * Note that changes made by any members or contributors of the VideoLAN team
* (i.e. changes that were checked in into one of VideoLAN's source code * (i.e. changes that were checked in exclusively into one of VideoLAN's source code
* repositories) are licensed under the GNU General Public License version 2, * repositories) are licensed under the GNU General Public License version 2,
* or (at your option) any later version. * or (at your option) any later version.
* Thus, the following statements apply to our changes: * Thus, the following statements apply to our changes:
* *
* Copyright (C) 2006 the VideoLAN team * Copyright (C) 2006-2007 the VideoLAN team
* Authors: Eric Petit <titer@m0k.org> * Authors: Eric Petit <titer@m0k.org>
* Felix Kühne <fkuehne at videolan dot org> * Felix Kühne <fkuehne at videolan dot org>
* *
...@@ -61,23 +61,25 @@ ...@@ -61,23 +61,25 @@
enum AppleRemoteEventIdentifier enum AppleRemoteEventIdentifier
{ {
kRemoteButtonVolume_Plus=0, kRemoteButtonVolume_Plus =1<<1,
kRemoteButtonVolume_Minus, kRemoteButtonVolume_Minus =1<<2,
kRemoteButtonMenu, kRemoteButtonMenu =1<<3,
kRemoteButtonPlay, kRemoteButtonPlay =1<<4,
kRemoteButtonRight, kRemoteButtonRight =1<<5,
kRemoteButtonLeft, kRemoteButtonLeft =1<<6,
kRemoteButtonRight_Hold, kRemoteButtonRight_Hold =1<<7,
kRemoteButtonLeft_Hold, kRemoteButtonLeft_Hold =1<<8,
kRemoteButtonMenu_Hold, kRemoteButtonMenu_Hold =1<<9,
kRemoteButtonPlay_Sleep, kRemoteButtonPlay_Sleep =1<<10,
kRemoteControl_Switched kRemoteControl_Switched =1<<11,
kRemoteButtonVolume_Plus_Hold =1<<12,
kRemoteButtonVolume_Minus_Hold =1<<13
}; };
typedef enum AppleRemoteEventIdentifier AppleRemoteEventIdentifier; typedef enum AppleRemoteEventIdentifier AppleRemoteEventIdentifier;
/* Encapsulates usage of the apple remote control /* Encapsulates usage of the apple remote control
This class is implemented as a singleton as there is exactly one remote per machine (until now) This class is implemented as a singleton as there is exactly one remote per machine (until now)
The class is not thread safe The class is not thread safe
*/ */
@interface AppleRemote : NSObject { @interface AppleRemote : NSObject {
IOHIDDeviceInterface** hidDeviceInterface; IOHIDDeviceInterface** hidDeviceInterface;
...@@ -86,13 +88,24 @@ typedef enum AppleRemoteEventIdentifier AppleRemoteEventIdentifier; ...@@ -86,13 +88,24 @@ typedef enum AppleRemoteEventIdentifier AppleRemoteEventIdentifier;
NSMutableDictionary* cookieToButtonMapping; NSMutableDictionary* cookieToButtonMapping;
BOOL openInExclusiveMode; BOOL openInExclusiveMode;
BOOL simulatePlusMinusHold;
BOOL processesBacklog;
/* state for simulating plus/minus hold */
BOOL lastEventSimulatedHold;
AppleRemoteEventIdentifier lastPlusMinusEvent;
NSTimeInterval lastPlusMinusEventTime;
int remoteId; int remoteId;
unsigned int clickCountEnabledButtons;
NSTimeInterval maxClickTimeDifference;
NSTimeInterval lastClickCountEventTime;
AppleRemoteEventIdentifier lastClickCountEvent;
unsigned int eventClickCount;
IBOutlet id delegate; IBOutlet id delegate;
} }
- (void) setRemoteId: (int) aValue;
- (int) remoteId; - (int) remoteId;
- (BOOL) isRemoteAvailable; - (BOOL) isRemoteAvailable;
...@@ -103,6 +116,42 @@ typedef enum AppleRemoteEventIdentifier AppleRemoteEventIdentifier; ...@@ -103,6 +116,42 @@ typedef enum AppleRemoteEventIdentifier AppleRemoteEventIdentifier;
- (BOOL) isOpenInExclusiveMode; - (BOOL) isOpenInExclusiveMode;
- (void) setOpenInExclusiveMode: (BOOL) value; - (void) setOpenInExclusiveMode: (BOOL) value;
/* click counting makes it possible to recognize if the user has pressed a button repeatedly
* click counting does delay each event as it has to wait if there is another event (second click)
* therefore there is a slight time difference (maximumClickCountTimeDifference) between a single click
* of the user and the call of your delegate method
* click counting can be enabled individually for specific buttons. Use the property clickCountEnableButtons
* to set the buttons for which click counting shall be enabled */
- (BOOL) clickCountingEnabled;
- (void) setClickCountingEnabled: (BOOL) value;
- (unsigned int) clickCountEnabledButtons;
- (void) setClickCountEnabledButtons: (unsigned int)value;
/* the maximum time difference till which clicks are recognized as multi clicks */
- (NSTimeInterval) maximumClickCountTimeDifference;
- (void) setMaximumClickCountTimeDifference: (NSTimeInterval) timeDiff;
/* When your application needs to much time on the main thread when processing an event other events
* may already be received which are put on a backlog. As soon as your main thread
* has some spare time this backlog is processed and may flood your delegate with calls.
* Backlog processing is turned off by default. */
- (BOOL) processesBacklog;
- (void) setProcessesBacklog: (BOOL) value;
/* Sets an NSApplication delegate which starts listening when application is becoming active
* and stops listening when application resigns being active.
* If an NSApplication delegate has been already set all method calls will be forwarded to this delegate, too. */
- (BOOL) listeningOnAppActivate;
- (void) setListeningOnAppActivate: (BOOL) value;
/* Simulating plus/minus hold does deactivate sending of individual requests for plus/minus pressed down/released.
* Instead special hold events are being triggered when the user is pressing and holding plus/minus for a small period.
* With simulating enabled the plus/minus buttons do behave as the left/right buttons */
- (BOOL) simulatesPlusMinusHold;
- (void) setSimulatesPlusMinusHold: (BOOL) value;
/* Delegates are not retained */
- (void) setDelegate: (id) delegate; - (void) setDelegate: (id) delegate;
- (id) delegate; - (id) delegate;
...@@ -116,15 +165,15 @@ typedef enum AppleRemoteEventIdentifier AppleRemoteEventIdentifier; ...@@ -116,15 +165,15 @@ typedef enum AppleRemoteEventIdentifier AppleRemoteEventIdentifier;
@end @end
/* Method definitions for the delegate of the AppleRemote class /* Method definitions for the delegate of the AppleRemote class */
*/
@interface NSObject(NSAppleRemoteDelegate) @interface NSObject(NSAppleRemoteDelegate)
- (void) appleRemoteButton: (AppleRemoteEventIdentifier)buttonIdentifier pressedDown: (BOOL) pressedDown; - (void) appleRemoteButton: (AppleRemoteEventIdentifier)buttonIdentifier pressedDown: (BOOL) pressedDown clickCount: (unsigned int) count;
@end @end
@interface AppleRemote (PrivateMethods) @interface AppleRemote (PrivateMethods)
- (void) setRemoteId: (int) aValue;
- (NSDictionary*) cookieToButtonMapping; - (NSDictionary*) cookieToButtonMapping;
- (IOHIDQueueInterface**) queue; - (IOHIDQueueInterface**) queue;
- (IOHIDDeviceInterface**) hidDeviceInterface; - (IOHIDDeviceInterface**) hidDeviceInterface;
...@@ -137,3 +186,14 @@ typedef enum AppleRemoteEventIdentifier AppleRemoteEventIdentifier; ...@@ -137,3 +186,14 @@ typedef enum AppleRemoteEventIdentifier AppleRemoteEventIdentifier;
- (BOOL) initializeCookies; - (BOOL) initializeCookies;
- (BOOL) openDevice; - (BOOL) openDevice;
@end @end
/* A NSApplication delegate which is used to activate and deactivate listening to the remote control
* dependent on the activation state of your application.
* All events are delegated to the original NSApplication delegate if necessary */
@interface AppleRemoteApplicationDelegate : NSObject {
id applicationDelegate;
}
- (id) initWithApplicationDelegate: (id) delegate;
- (id) applicationDelegate;
@end
...@@ -27,12 +27,12 @@ ...@@ -27,12 +27,12 @@
***************************************************************************** *****************************************************************************
* *
* Note that changes made by any members or contributors of the VideoLAN team * Note that changes made by any members or contributors of the VideoLAN team
* (i.e. changes that were checked in to one of VideoLAN's source code * (i.e. changes that were exclusively checked in to one of VideoLAN's source code
* repositories) are licensed under the GNU General Public License version 2, * repositories) are licensed under the GNU General Public License version 2,
* or (at your option) any later version. * or (at your option) any later version.
* Thus, the following statements apply to our changes: * Thus, the following statements apply to our changes:
* *
* Copyright (C) 2006 the VideoLAN team * Copyright (C) 2006-2007 the VideoLAN team
* Authors: Eric Petit <titer@m0k.org> * Authors: Eric Petit <titer@m0k.org>
* Felix Kühne <fkuehne at videolan dot org> * Felix Kühne <fkuehne at videolan dot org>
* *
...@@ -58,20 +58,21 @@ ...@@ -58,20 +58,21 @@
const char* AppleRemoteDeviceName = "AppleIRController"; const char* AppleRemoteDeviceName = "AppleIRController";
const int REMOTE_SWITCH_COOKIE=19; const int REMOTE_SWITCH_COOKIE=19;
const NSTimeInterval DEFAULT_MAXIMUM_CLICK_TIME_DIFFERENCE=0.35;
const NSTimeInterval HOLD_RECOGNITION_TIME_INTERVAL=0.4;
@implementation AppleRemote @implementation AppleRemote
- (id) init #pragma public interface
{
self = [super init];
if ( self == [super init] ) { - (id) init {
if ( self = [super init] ) {
openInExclusiveMode = YES; openInExclusiveMode = YES;
queue = NULL; queue = NULL;
hidDeviceInterface = NULL; hidDeviceInterface = NULL;
cookieToButtonMapping = [[NSMutableDictionary alloc] init]; cookieToButtonMapping = [[NSMutableDictionary alloc] init];
if( MACOS_VERSION < 10.5f ) // internal VLC definition if( MACOS_VERSION < 10.5f )
{ {
/* use the traditional cookies for Tiger (and Panther, if it is supported by the frame app) */ /* use the traditional cookies for Tiger (and Panther, if it is supported by the frame app) */
[cookieToButtonMapping setObject:[NSNumber numberWithInt:kRemoteButtonVolume_Plus] forKey:@"14_12_11_6_"]; [cookieToButtonMapping setObject:[NSNumber numberWithInt:kRemoteButtonVolume_Plus] forKey:@"14_12_11_6_"];
...@@ -102,6 +103,9 @@ const int REMOTE_SWITCH_COOKIE=19; ...@@ -102,6 +103,9 @@ const int REMOTE_SWITCH_COOKIE=19;
[cookieToButtonMapping setObject:[NSNumber numberWithInt:kRemoteControl_Switched] forKey:@"19_"]; [cookieToButtonMapping setObject:[NSNumber numberWithInt:kRemoteControl_Switched] forKey:@"19_"];
} }
/* defaults */
[self setSimulatesPlusMinusHold: YES];
maxClickTimeDifference = DEFAULT_MAXIMUM_CLICK_TIME_DIFFERENCE;
} }
return self; return self;
...@@ -113,9 +117,15 @@ const int REMOTE_SWITCH_COOKIE=19; ...@@ -113,9 +117,15 @@ const int REMOTE_SWITCH_COOKIE=19;
[super dealloc]; [super dealloc];
} }
- (void) setRemoteId: (int) value { /* this was added by the VideoLAN team to ensure Leopard-compatibility and is VLC-only */
remoteId = value; #if GC_ENABLED
- (void)finalize
{
[self stopListening: self];
[super finalize];
} }
#endif
- (int) remoteId { - (int) remoteId {
return remoteId; return remoteId;
} }
...@@ -142,11 +152,14 @@ const int REMOTE_SWITCH_COOKIE=19; ...@@ -142,11 +152,14 @@ const int REMOTE_SWITCH_COOKIE=19;
} }
} }
/* Delegates are not retained!
* http://developer.apple.com/documentation/Cocoa/Conceptual/CocoaFundamentals/CommunicatingWithObjects/chapter_6_section_4.html
* Delegating objects do not (and should not) retain their delegates.
* However, clients of delegating objects (applications, usually) are responsible for ensuring that their delegates are around
* to receive delegation messages. To do this, they may have to retain the delegate. */
- (void) setDelegate: (id) _delegate { - (void) setDelegate: (id) _delegate {
if ([_delegate respondsToSelector:@selector(appleRemoteButton:pressedDown:)]==NO) return; if (_delegate && [_delegate respondsToSelector:@selector(appleRemoteButton:pressedDown:clickCount:)]==NO) return;
[_delegate retain];
[delegate release];
delegate = _delegate; delegate = _delegate;
} }
- (id) delegate { - (id) delegate {
...@@ -160,6 +173,64 @@ const int REMOTE_SWITCH_COOKIE=19; ...@@ -160,6 +173,64 @@ const int REMOTE_SWITCH_COOKIE=19;
openInExclusiveMode = value; openInExclusiveMode = value;
} }
- (BOOL) clickCountingEnabled {
return clickCountEnabledButtons != 0;
}
- (void) setClickCountingEnabled: (BOOL) value {
if (value) {
[self setClickCountEnabledButtons: kRemoteButtonVolume_Plus | kRemoteButtonVolume_Minus | kRemoteButtonPlay | kRemoteButtonLeft | kRemoteButtonRight | kRemoteButtonMenu];
} else {
[self setClickCountEnabledButtons: 0];
}
}
- (unsigned int) clickCountEnabledButtons {
return clickCountEnabledButtons;
}
- (void) setClickCountEnabledButtons: (unsigned int)value {
clickCountEnabledButtons = value;
}
- (NSTimeInterval) maximumClickCountTimeDifference {
return maxClickTimeDifference;
}
- (void) setMaximumClickCountTimeDifference: (NSTimeInterval) timeDiff {
maxClickTimeDifference = timeDiff;
}
- (BOOL) processesBacklog {
return processesBacklog;
}
- (void) setProcessesBacklog: (BOOL) value {
processesBacklog = value;
}
- (BOOL) listeningOnAppActivate {
id appDelegate = [NSApp delegate];
return (appDelegate!=nil && [appDelegate isKindOfClass: [AppleRemoteApplicationDelegate class]]);
}
- (void) setListeningOnAppActivate: (BOOL) value {
if (value) {
if ([self listeningOnAppActivate]) return;
AppleRemoteApplicationDelegate* appDelegate = [[AppleRemoteApplicationDelegate alloc] initWithApplicationDelegate: [NSApp delegate]];
/* NSApp does not retain its delegate therefore we keep retain count on 1 */
[NSApp setDelegate: appDelegate];
} else {
if ([self listeningOnAppActivate]==NO) return;
AppleRemoteApplicationDelegate* appDelegate = (AppleRemoteApplicationDelegate*)[NSApp delegate];
id previousAppDelegate = [appDelegate applicationDelegate];
[NSApp setDelegate: previousAppDelegate];
[appDelegate release];
}
}
- (BOOL) simulatesPlusMinusHold {
return simulatePlusMinusHold;
}
- (void) setSimulatesPlusMinusHold: (BOOL) value {
simulatePlusMinusHold = value;
}
- (IBAction) startListening: (id) sender { - (IBAction) startListening: (id) sender {
if ([self isListeningToRemote]) return; if ([self isListeningToRemote]) return;
...@@ -257,6 +328,10 @@ static AppleRemote* sharedInstance=nil; ...@@ -257,6 +328,10 @@ static AppleRemote* sharedInstance=nil;
@implementation AppleRemote (PrivateMethods) @implementation AppleRemote (PrivateMethods)
- (void) setRemoteId: (int) value {
remoteId = value;
}
- (IOHIDQueueInterface**) queue { - (IOHIDQueueInterface**) queue {
return queue; return queue;
} }
...@@ -270,15 +345,137 @@ static AppleRemote* sharedInstance=nil; ...@@ -270,15 +345,137 @@ static AppleRemote* sharedInstance=nil;
return cookieToButtonMapping; return cookieToButtonMapping;
} }
- (NSString*) validCookieSubstring: (NSString*) cookieString {
if (cookieString == nil || [cookieString length] == 0) return nil;
NSEnumerator* keyEnum = [[self cookieToButtonMapping] keyEnumerator];
NSString* key;
while(key = [keyEnum nextObject]) {
NSRange range = [cookieString rangeOfString:key];
if (range.location == 0) return key;
}
return nil;
}
- (void) sendSimulatedPlusMinusEvent: (id) time {
BOOL startSimulateHold = NO;
AppleRemoteEventIdentifier event = lastPlusMinusEvent;
@synchronized(self) {
startSimulateHold = (lastPlusMinusEvent>0 && lastPlusMinusEventTime == [time doubleValue]);
}
if (startSimulateHold) {
lastEventSimulatedHold = YES;
event = (event==kRemoteButtonVolume_Plus) ? kRemoteButtonVolume_Plus_Hold : kRemoteButtonVolume_Minus_Hold;
[delegate appleRemoteButton:event pressedDown: YES clickCount: 1];
}
}
- (void) sendRemoteButtonEvent: (AppleRemoteEventIdentifier) event pressedDown: (BOOL) pressedDown {
if (delegate) {
if (simulatePlusMinusHold) {
if (event == kRemoteButtonVolume_Plus || event == kRemoteButtonVolume_Minus) {
if (pressedDown) {
lastPlusMinusEvent = event;
lastPlusMinusEventTime = [NSDate timeIntervalSinceReferenceDate];
[self performSelector:@selector(sendSimulatedPlusMinusEvent:)
withObject:[NSNumber numberWithDouble:lastPlusMinusEventTime]
afterDelay:HOLD_RECOGNITION_TIME_INTERVAL];
return;
} else {
if (lastEventSimulatedHold) {
event = (event==kRemoteButtonVolume_Plus) ? kRemoteButtonVolume_Plus_Hold : kRemoteButtonVolume_Minus_Hold;
lastPlusMinusEvent = 0;
lastEventSimulatedHold = NO;
} else {
@synchronized(self) {
lastPlusMinusEvent = 0;
}
pressedDown = YES;
}
}
}
}
if (([self clickCountEnabledButtons] & event) == event) {
if (pressedDown==NO && (event == kRemoteButtonVolume_Minus || event == kRemoteButtonVolume_Plus)) {
return; // this one is triggered automatically by the handler
}
NSNumber* eventNumber;
NSNumber* timeNumber;
@synchronized(self) {
lastClickCountEventTime = [NSDate timeIntervalSinceReferenceDate];
if (lastClickCountEvent == event) {
eventClickCount = eventClickCount + 1;
} else {
eventClickCount = 1;
}
lastClickCountEvent = event;
timeNumber = [NSNumber numberWithDouble:lastClickCountEventTime];
eventNumber= [NSNumber numberWithUnsignedInt:event];
}
[self performSelector: @selector(executeClickCountEvent:)
withObject: [NSArray arrayWithObjects:eventNumber, timeNumber, nil]
afterDelay: maxClickTimeDifference];
} else {
[delegate appleRemoteButton:event pressedDown: pressedDown clickCount:1];
}
}
}
- (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)) {
// trigger a button release event, too
[NSThread sleepUntilDate: [NSDate dateWithTimeIntervalSinceNow:0.1]];
[delegate appleRemoteButton:event pressedDown: NO clickCount:finalClickCount];
}
}
}
- (void) handleEventWithCookieString: (NSString*) cookieString sumOfValues: (SInt32) sumOfValues { - (void) handleEventWithCookieString: (NSString*) cookieString sumOfValues: (SInt32) sumOfValues {
/*
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]; NSNumber* buttonId = [[self cookieToButtonMapping] objectForKey: cookieString];
if (buttonId != nil) { if (buttonId != nil) {
if (delegate) { [self sendRemoteButtonEvent: [buttonId intValue] pressedDown: (sumOfValues>0)];
[delegate appleRemoteButton:[buttonId intValue] pressedDown: (sumOfValues>0)];
}
} else { } else {
// let's see if a number of events are stored in the cookie string. this does
// happen when the main thread is too busy to handle all incoming events in time.
NSString* subCookieString;
NSString* lastSubCookieString=nil;
while(subCookieString = [self validCookieSubstring: cookieString]) {
cookieString = [cookieString substringFromIndex: [subCookieString length]];
lastSubCookieString = subCookieString;
if (processesBacklog) [self handleEventWithCookieString: subCookieString sumOfValues:sumOfValues];
}
if (processesBacklog == NO && lastSubCookieString != nil) {
// process the last event of the backlog and assume that the button is not pressed down any longer.
// The events in the backlog do not seem to be in order and therefore (in rare cases) the last event might be
// a button pressed down event while in reality the user has released it.
// NSLog(@"processing last event of backlog");
[self handleEventWithCookieString: lastSubCookieString sumOfValues:0];
}
if ([cookieString length] > 0) {
NSLog(@"Unknown button for cookiestring %@", cookieString); NSLog(@"Unknown button for cookiestring %@", cookieString);
} }
}
} }
@end @end
...@@ -299,19 +496,20 @@ static void QueueCallbackFunction(void* target, IOReturn result, void* refcon, ...@@ -299,19 +496,20 @@ static void QueueCallbackFunction(void* target, IOReturn result, void* refcon,
if ( result != kIOReturnSuccess ) if ( result != kIOReturnSuccess )
continue; 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) {
[remote setRemoteId: event.value]; [remote setRemoteId: event.value];
[remote handleEventWithCookieString: @"19_" sumOfValues: 0]; [remote handleEventWithCookieString: @"19_" sumOfValues: 0];
} else { } else {
if (((int)event.elementCookie)!=5) {
sumOfValues+=event.value; sumOfValues+=event.value;
[cookieString appendString:[NSString stringWithFormat:@"%d_", event.elementCookie]]; [cookieString appendString:[NSString stringWithFormat:@"%d_", event.elementCookie]];
} }
}
//printf("%d %d %d\n", event.elementCookie, event.value, event.longValue);
} }
[remote handleEventWithCookieString: cookieString sumOfValues: sumOfValues]; [remote handleEventWithCookieString: cookieString sumOfValues: sumOfValues];
} }
@implementation AppleRemote (IOKitMethods) @implementation AppleRemote (IOKitMethods)
...@@ -386,10 +584,10 @@ static void QueueCallbackFunction(void* target, IOReturn result, void* refcon, ...@@ -386,10 +584,10 @@ static void QueueCallbackFunction(void* target, IOReturn result, void* refcon,
if (!handle || !(*handle)) return NO; if (!handle || !(*handle)) return NO;
// Copy all elements, since we're grabbing most of the elements /* Copy all elements, since we're grabbing most of the elements
// for this device anyway, and thus, it's faster to iterate them * for this device anyway, and thus, it's faster to iterate them
// ourselves. When grabbing only one or two elements, a matching * ourselves. When grabbing only one or two elements, a matching
// dictionary should be passed in here instead of NULL. * dictionary should be passed in here instead of NULL. */
success = (*handle)->copyMatchingElements(handle, NULL, (CFArrayRef*)&elements); success = (*handle)->copyMatchingElements(handle, NULL, (CFArrayRef*)&elements);
if (success == kIOReturnSuccess) { if (success == kIOReturnSuccess) {
...@@ -400,7 +598,7 @@ static void QueueCallbackFunction(void* target, IOReturn result, void* refcon, ...@@ -400,7 +598,7 @@ static void QueueCallbackFunction(void* target, IOReturn result, void* refcon,
memset(cookies, 0, sizeof(IOHIDElementCookie) * NUMBER_OF_APPLE_REMOTE_ACTIONS); memset(cookies, 0, sizeof(IOHIDElementCookie) * NUMBER_OF_APPLE_REMOTE_ACTIONS);
*/ */
allCookies = [[NSMutableArray alloc] init]; allCookies = [[NSMutableArray alloc] init];
unsigned int i; int i;
for (i=0; i< [elements count]; i++) { for (i=0; i< [elements count]; i++) {
element = [elements objectAtIndex:i]; element = [elements objectAtIndex:i];
...@@ -441,7 +639,7 @@ static void QueueCallbackFunction(void* target, IOReturn result, void* refcon, ...@@ -441,7 +639,7 @@ static void QueueCallbackFunction(void* target, IOReturn result, void* refcon,
if (queue) { if (queue) {
result = (*queue)->create(queue, 0, 12); //depth: maximum number of elements in queue before oldest elements in queue begin to be lost. 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; int i=0;
for(i=0; i<[allCookies count]; i++) { for(i=0; i<[allCookies count]; i++) {
IOHIDElementCookie cookie = (IOHIDElementCookie)[[allCookies objectAtIndex:i] intValue]; IOHIDElementCookie cookie = (IOHIDElementCookie)[[allCookies objectAtIndex:i] intValue];
(*queue)->addElement(queue, cookie, 0); (*queue)->addElement(queue, cookie, 0);
...@@ -471,3 +669,67 @@ static void QueueCallbackFunction(void* target, IOReturn result, void* refcon, ...@@ -471,3 +669,67 @@ static void QueueCallbackFunction(void* target, IOReturn result, void* refcon,
} }
@end @end
@implementation AppleRemoteApplicationDelegate
- (id) initWithApplicationDelegate: (id) delegate {
if (self = [super init]) {
applicationDelegate = [delegate retain];
}
return self;
}
- (void) dealloc {
NSLog(@"Dealloc");
[applicationDelegate release];
[super dealloc];
}
- (id) applicationDelegate {
return applicationDelegate;
}
- (void)applicationWillBecomeActive:(NSNotification *)aNotification {
if ([applicationDelegate respondsToSelector: @selector(applicationWillBecomeActive:)]) {
[applicationDelegate applicationWillBecomeActive: aNotification];
}
}
- (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];
}
}
- (void)applicationDidResignActive:(NSNotification *)aNotification {
if ([applicationDelegate respondsToSelector: @selector(applicationDidResignActive:)]) {
[applicationDelegate applicationDidResignActive: aNotification];
}
}
- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector {
NSMethodSignature* signature = [super methodSignatureForSelector: aSelector];
if (signature == nil && applicationDelegate != nil) {
signature = [applicationDelegate methodSignatureForSelector: aSelector];
}
return signature;
}
- (void)forwardInvocation:(NSInvocation *)invocation {
SEL aSelector = [invocation selector];
if (applicationDelegate==nil || [applicationDelegate respondsToSelector:aSelector]==NO) {
[super forwardInvocation: invocation];
return;
}
[invocation invokeWithTarget:applicationDelegate];
}
@end
...@@ -459,6 +459,9 @@ ...@@ -459,6 +459,9 @@
var_Get( p_playlist, "fullscreen", &val ); var_Get( p_playlist, "fullscreen", &val );
var_Set( p_playlist, "fullscreen", (vlc_value_t)!val.b_bool ); var_Set( p_playlist, "fullscreen", (vlc_value_t)!val.b_bool );
} }
else
NSLog( sender );
if( p_playlist ) vlc_object_release( (vlc_object_t *)p_playlist ); if( p_playlist ) vlc_object_release( (vlc_object_t *)p_playlist );
} }
......
...@@ -289,7 +289,7 @@ struct intf_sys_t ...@@ -289,7 +289,7 @@ struct intf_sys_t
int i_lastShownVolume; int i_lastShownVolume;
AppleRemote * o_remote; AppleRemote * o_remote;
BOOL b_left_right_remote_button_hold; /* true as long as the user holds the left or right button on the remote control */ BOOL b_remote_button_hold; /* true as long as the user holds the left,right,plus or minus on the remote control */
} }
+ (VLCMain *)sharedInstance; + (VLCMain *)sharedInstance;
......
...@@ -351,6 +351,7 @@ static VLCMain *_o_sharedMainInstance = nil; ...@@ -351,6 +351,7 @@ static VLCMain *_o_sharedMainInstance = nil;
i_lastShownVolume = -1; i_lastShownVolume = -1;
o_remote = [[AppleRemote alloc] init]; o_remote = [[AppleRemote alloc] init];
[o_remote setClickCountEnabledButtons: kRemoteButtonPlay];
[o_remote setDelegate: _o_sharedMainInstance]; [o_remote setDelegate: _o_sharedMainInstance];
return _o_sharedMainInstance; return _o_sharedMainInstance;
...@@ -719,22 +720,31 @@ static VLCMain *_o_sharedMainInstance = nil; ...@@ -719,22 +720,31 @@ static VLCMain *_o_sharedMainInstance = nil;
[o_remote stopListening: self]; [o_remote stopListening: self];
} }
/* Helper method for the remote control interface in order to trigger forward/backward /* Helper method for the remote control interface in order to trigger forward/backward and volume
as long as the user holds the left/right button */ increase/decrease as long as the user holds the left/right, plus/minus button */
- (void) triggerMovieStepForRemoteButton: (NSNumber*) buttonIdentifierNumber - (void) executeHoldActionForRemoteButton: (NSNumber*) buttonIdentifierNumber
{ {
if (b_left_right_remote_button_hold) { if (b_remote_button_hold)
switch([buttonIdentifierNumber intValue]) { {
switch([buttonIdentifierNumber intValue])
{
case kRemoteButtonRight_Hold: case kRemoteButtonRight_Hold:
[o_controls forward: self]; [o_controls forward: self];
break; break;
case kRemoteButtonLeft_Hold: case kRemoteButtonLeft_Hold:
[o_controls backward: self]; [o_controls backward: self];
break; break;
case kRemoteButtonVolume_Plus_Hold:
[o_controls volumeUp: self];
break;
case kRemoteButtonVolume_Minus_Hold:
[o_controls volumeDown: self];
break;
} }
if (b_left_right_remote_button_hold) { if (b_remote_button_hold)
{
/* trigger event */ /* trigger event */
[self performSelector:@selector(triggerMovieStepForRemoteButton:) [self performSelector:@selector(executeHoldActionForRemoteButton:)
withObject:buttonIdentifierNumber withObject:buttonIdentifierNumber
afterDelay:0.25]; afterDelay:0.25];
} }
...@@ -742,29 +752,28 @@ static VLCMain *_o_sharedMainInstance = nil; ...@@ -742,29 +752,28 @@ static VLCMain *_o_sharedMainInstance = nil;
} }
/* Apple Remote callback */ /* Apple Remote callback */
- (void)appleRemoteButton:(AppleRemoteEventIdentifier)buttonIdentifier - (void) appleRemoteButton: (AppleRemoteEventIdentifier)buttonIdentifier
pressedDown:(BOOL)pressedDown pressedDown: (BOOL) pressedDown
clickCount: (unsigned int) count
{ {
switch( buttonIdentifier ) switch( buttonIdentifier )
{ {
case kRemoteButtonPlay: case kRemoteButtonPlay:
if (count >= 2)
{
/* we're cheating here to convince o_controls to toggle fullscreen */
[o_controls windowAction: o_mi_fullscreen];
}
else
{
[o_controls play: self]; [o_controls play: self];
}
break; break;
case kRemoteButtonVolume_Plus: case kRemoteButtonVolume_Plus:
/* there are two events when the plus or minus button is pressed
one when the button is pressed down and one when the button is released */
if( pressedDown )
{
[o_controls volumeUp: self]; [o_controls volumeUp: self];
}
break; break;
case kRemoteButtonVolume_Minus: case kRemoteButtonVolume_Minus:
/* there are two events when the plus or minus button is pressed
one when the button is pressed down and one when the button is released */
if( pressedDown )
{
[o_controls volumeDown: self]; [o_controls volumeDown: self];
}
break; break;
case kRemoteButtonRight: case kRemoteButtonRight:
[o_controls next: self]; [o_controls next: self];
...@@ -774,17 +783,20 @@ static VLCMain *_o_sharedMainInstance = nil; ...@@ -774,17 +783,20 @@ static VLCMain *_o_sharedMainInstance = nil;
break; break;
case kRemoteButtonRight_Hold: case kRemoteButtonRight_Hold:
case kRemoteButtonLeft_Hold: case kRemoteButtonLeft_Hold:
case kRemoteButtonVolume_Plus_Hold:
case kRemoteButtonVolume_Minus_Hold:
/* simulate an event as long as the user holds the button */ /* simulate an event as long as the user holds the button */
b_left_right_remote_button_hold = pressedDown; b_remote_button_hold = pressedDown;
if( pressedDown ) if( pressedDown )
{ {
NSNumber* buttonIdentifierNumber = [NSNumber numberWithInt: buttonIdentifier]; NSNumber* buttonIdentifierNumber = [NSNumber numberWithInt: buttonIdentifier];
[self performSelector:@selector(triggerMovieStepForRemoteButton:) [self performSelector:@selector(executeHoldActionForRemoteButton:)
withObject:buttonIdentifierNumber]; withObject:buttonIdentifierNumber];
} }
break; break;
case kRemoteButtonMenu: case kRemoteButtonMenu:
[o_controls windowAction: self]; /* we're cheating here to convince o_controls to toggle fullscreen */
[o_controls windowAction: o_mi_fullscreen];
break; break;
default: default:
/* Add here whatever you want other buttons to do */ /* Add here whatever you want other buttons to do */
......
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