aboutsummaryrefslogtreecommitdiff
path: root/tools/EventClients
diff options
context:
space:
mode:
authormaestrodd <maestrodd@svn>2009-10-23 14:54:08 +0000
committermaestrodd <maestrodd@svn>2009-10-23 14:54:08 +0000
commite29c9df6d5228423fcdbad090ef64277e2eb146d (patch)
tree2a981446ea1e71bf32cad736a028528d82469115 /tools/EventClients
parent0ddd418f491ca9cb3338e583fadd67a5a4bc1cde (diff)
[OSX] changed to HIDRemote backend for XBMCHelper (thanks to IOSpirit for openingn it up) + few cosmetics
git-svn-id: https://xbmc.svn.sourceforge.net/svnroot/xbmc/trunk@23927 568bbfeb-2a22-0410-94d2-cc84cf5bfa90
Diffstat (limited to 'tools/EventClients')
-rw-r--r--tools/EventClients/Clients/OSXRemote/HIDRemote.h484
-rw-r--r--tools/EventClients/Clients/OSXRemote/HIDRemote.m1544
-rw-r--r--tools/EventClients/Clients/OSXRemote/RemoteControlWrapper/AppleRemote.h44
-rw-r--r--tools/EventClients/Clients/OSXRemote/RemoteControlWrapper/AppleRemote.m108
-rw-r--r--tools/EventClients/Clients/OSXRemote/RemoteControlWrapper/GlobalKeyboardDevice.h49
-rw-r--r--tools/EventClients/Clients/OSXRemote/RemoteControlWrapper/GlobalKeyboardDevice.m241
-rw-r--r--tools/EventClients/Clients/OSXRemote/RemoteControlWrapper/HIDRemoteControlDevice.h77
-rw-r--r--tools/EventClients/Clients/OSXRemote/RemoteControlWrapper/HIDRemoteControlDevice.m547
-rw-r--r--tools/EventClients/Clients/OSXRemote/RemoteControlWrapper/IRKeyboardEmu.h16
-rw-r--r--tools/EventClients/Clients/OSXRemote/RemoteControlWrapper/IRKeyboardEmu.m26
-rw-r--r--tools/EventClients/Clients/OSXRemote/RemoteControlWrapper/KeyspanFrontRowControl.h39
-rw-r--r--tools/EventClients/Clients/OSXRemote/RemoteControlWrapper/KeyspanFrontRowControl.m87
-rw-r--r--tools/EventClients/Clients/OSXRemote/RemoteControlWrapper/MultiClickRemoteBehavior.h90
-rw-r--r--tools/EventClients/Clients/OSXRemote/RemoteControlWrapper/MultiClickRemoteBehavior.m210
-rw-r--r--tools/EventClients/Clients/OSXRemote/RemoteControlWrapper/RemoteControl.h102
-rw-r--r--tools/EventClients/Clients/OSXRemote/RemoteControlWrapper/RemoteControl.m102
-rw-r--r--tools/EventClients/Clients/OSXRemote/RemoteControlWrapper/RemoteControlContainer.h38
-rw-r--r--tools/EventClients/Clients/OSXRemote/RemoteControlWrapper/RemoteControlContainer.m114
-rw-r--r--tools/EventClients/Clients/OSXRemote/XBMCHelper.h7
-rw-r--r--tools/EventClients/Clients/OSXRemote/XBMCHelper.m391
-rw-r--r--tools/EventClients/Clients/OSXRemote/XBMCHelper.xcodeproj/project.pbxproj64
-rw-r--r--tools/EventClients/Clients/OSXRemote/xbmchelper_main.mm32
22 files changed, 2293 insertions, 2119 deletions
diff --git a/tools/EventClients/Clients/OSXRemote/HIDRemote.h b/tools/EventClients/Clients/OSXRemote/HIDRemote.h
new file mode 100644
index 0000000000..d2a7cf8796
--- /dev/null
+++ b/tools/EventClients/Clients/OSXRemote/HIDRemote.h
@@ -0,0 +1,484 @@
+//
+// HIDRemote.h
+// HIDRemote V1.0
+//
+// Created by Felix Schwarz on 06.04.07.
+// Copyright 2007-2009 IOSPIRIT GmbH. All rights reserved.
+//
+// ** LICENSE *************************************************************************
+//
+// Copyright (c) 2007-2009 IOSPIRIT GmbH
+// 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
+// SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+// TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+// 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.
+//
+// ************************************************************************************
+
+#import <Cocoa/Cocoa.h>
+
+#include <Carbon/Carbon.h>
+
+#include <unistd.h>
+#include <mach/mach.h>
+#include <sys/types.h>
+
+#include <IOKit/IOKitLib.h>
+#include <IOKit/IOCFPlugIn.h>
+#include <IOKit/IOMessage.h>
+#include <IOKit/hid/IOHIDKeys.h>
+#include <IOKit/hid/IOHIDLib.h>
+#include <IOKit/hid/IOHIDUsageTables.h>
+#include <IOKit/hidsystem/IOHIDLib.h>
+#include <IOKit/hidsystem/IOHIDParameter.h>
+#include <IOKit/hidsystem/IOHIDShared.h>
+
+#pragma mark -- Enums / Codes --
+
+typedef enum
+{
+ kHIDRemoteModeNone = 0L,
+ kHIDRemoteModeShared, // Share the remote with others - let's you listen to the remote control events as long as noone has an exclusive lock on it
+ // (RECOMMENDED ONLY FOR SPECIAL PURPOSES)
+
+ kHIDRemoteModeExclusive, // Try to acquire an exclusive lock on the remote (NOT RECOMMENDED)
+
+ 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;
+
+typedef enum
+{
+ /* A code reserved for "no button" (needed for tracking) */
+ kHIDRemoteButtonCodeNone = 0L,
+
+ /* HID Remote standard codes - you'll be able to receive all of these in your HIDRemote delegate */
+ kHIDRemoteButtonCodePlus,
+ kHIDRemoteButtonCodeMinus,
+ kHIDRemoteButtonCodeLeft,
+ kHIDRemoteButtonCodeRight,
+ kHIDRemoteButtonCodePlayPause,
+ kHIDRemoteButtonCodeMenu,
+
+ /* Masks */
+ kHIDRemoteButtonCodeCodeMask = 0xFFL,
+ kHIDRemoteButtonCodeHoldMask = (1L << 16L),
+ kHIDRemoteButtonCodeSpecialMask = (1L << 17L),
+
+ /* Hold button codes */
+ kHIDRemoteButtonCodePlusHold = (kHIDRemoteButtonCodeHoldMask|kHIDRemoteButtonCodePlus),
+ kHIDRemoteButtonCodeMinusHold = (kHIDRemoteButtonCodeHoldMask|kHIDRemoteButtonCodeMinus),
+ kHIDRemoteButtonCodeLeftHold = (kHIDRemoteButtonCodeHoldMask|kHIDRemoteButtonCodeLeft),
+ kHIDRemoteButtonCodeRightHold = (kHIDRemoteButtonCodeHoldMask|kHIDRemoteButtonCodeRight),
+ kHIDRemoteButtonCodePlayPauseHold = (kHIDRemoteButtonCodeHoldMask|kHIDRemoteButtonCodePlayPause),
+ kHIDRemoteButtonCodeMenuHold = (kHIDRemoteButtonCodeHoldMask|kHIDRemoteButtonCodeMenu),
+
+ /* Special purpose codes */
+ kHIDRemoteButtonCodeIDChanged = (kHIDRemoteButtonCodeSpecialMask|(1L << 18L)), // (the ID of the connected remote has changed, you can safely ignore this)
+ #ifdef _HIDREMOTE_EXTENSIONS
+ #define _HIDREMOTE_EXTENSIONS_SECTION 1
+ #include "HIDRemoteAdditions.h"
+ #undef _HIDREMOTE_EXTENSIONS_SECTION
+ #endif /* _HIDREMOTE_EXTENSIONS */
+} HIDRemoteButtonCode;
+
+@class HIDRemote;
+
+#pragma mark -- Delegate protocol (mandatory) --
+@protocol HIDRemoteDelegate
+
+// Notification of button events
+- (void)hidRemote:(HIDRemote *)hidRemote // The instance of HIDRemote sending this
+ eventWithButton:(HIDRemoteButtonCode)buttonCode // Event for the button specified by code
+ isPressed:(BOOL)isPressed; // The button was pressed (YES) / released (NO)
+
+@optional
+
+// Notification of ID changes
+- (void)hidRemote:(HIDRemote *)hidRemote
+ remoteIDChangedOldID:(SInt32)old // Invoked when the user switched to a remote control with a different ID
+ newID:(SInt32)newID;
+
+// Notification about hardware additions/removals
+- (void)hidRemote:(HIDRemote *)hidRemote // Invoked when new hardware was found / added to HIDRemote's pool
+ foundNewHardwareWithAttributes:(NSMutableDictionary *)attributes;
+
+- (void)hidRemote:(HIDRemote *)hidRemote // Invoked when initialization of new hardware as requested failed
+ failedNewHardwareWithError:(NSError *)error;
+
+- (void)hidRemote:(HIDRemote *)hidRemote // Invoked when hardware was removed from HIDRemote's pool
+ releasedHardwareWithAttributes:(NSMutableDictionary *)attributes;
+
+// WARNING: Unless you know VERY PRECISELY what you are doing, do not implement any of the methods below.
+// Matching of newly found receiver hardware
+- (BOOL)hidRemote:(HIDRemote *)hidRemote // Invoked when new hardware is inspected
+ inspectNewHardwareWithService:(io_service_t)service //
+ prematchResult:(BOOL)prematchResult; // Return YES if HIDRemote should go on with this hardware and try
+ // to use it, or NO if it should not be persued further.
+
+// Exlusive lock lending
+- (BOOL)hidRemote:(HIDRemote *)hidRemote
+ lendExclusiveLockToApplicationWithInfo:(NSDictionary *)applicationInfo;
+
+- (void)hidRemote:(HIDRemote *)hidRemote
+ exclusiveLockReleasedByApplicationWithInfo:(NSDictionary *)applicationInfo;
+
+- (BOOL)hidRemote:(HIDRemote *)hidRemote
+ shouldRetryExclusiveLockWithInfo:(NSDictionary *)applicationInfo;
+
+@end
+
+
+#pragma mark -- Actual header file for class --
+
+@interface HIDRemote : NSObject
+{
+ // IOMasterPort
+ mach_port_t _masterPort;
+
+ // Notification ports
+ IONotificationPortRef _notifyPort;
+ CFRunLoopSourceRef _notifyRLSource;
+
+ // Matching iterator
+ io_iterator_t _matchingServicesIterator;
+
+ // Service attributes
+ NSMutableDictionary *_serviceAttribMap;
+
+ // Mode
+ HIDRemoteMode _mode;
+ BOOL _autoRecover;
+ NSTimer *_autoRecoveryTimer;
+
+ // Delegate
+ NSObject <HIDRemoteDelegate> *_delegate;
+
+ // Last seen ID
+ SInt32 _lastSeenRemoteID;
+
+ // Unused button codes
+ NSArray *_unusedButtonCodes;
+
+ // Simulate Plus/Minus Hold
+ BOOL _simulateHoldEvents;
+
+ // SecureEventInput workaround
+ BOOL _secureEventInputWorkAround;
+ BOOL _statusSecureEventInputWorkAroundEnabled;
+
+ // Exclusive lock lending
+ BOOL _exclusiveLockLending;
+ NSNumber *_waitForReturnByPID;
+ NSNumber *_returnToPID;
+}
+
+#pragma mark -- PUBLIC: Shared HID Remote --
+/*
+ DESCRIPTION
+ It is possible to alloc & init multiple instances of this class. However, this is not recommended unless
+ you subclass it and build something different. Instead of allocating & initializing the instance yourself,
+ you can make use of the +sharedHIDRemote singleton.
+
+ RESULT
+ The HIDRemote instance globally shared in your application. You should not -release the returned object.
+*/
++ (HIDRemote *)sharedHIDRemote;
+
+#pragma mark -- PUBLIC: System Information --
+/*
+ DESCRIPTION
+ Determine whether the Candelair driver version 1.7.0 or later is installed.
+
+ RESULT
+ YES, if it is installed. NO, if it isn't.
+*/
++ (BOOL)isCandelairInstalled;
+
+/*
+ DESCRIPTION
+ Determine whether the user needs to install the Candelair driver in order for your application to get
+ access to the IR Receiver in a specific mode.
+
+ RESULT
+ YES, if the user runs your application on an operating system version that makes the installation of
+ the Candelair driver necessary for your application to get access to the IR Receiver in the specified
+ mode.
+ NO, if the operating system version in use either doesn't make the installation of the Candelair driver
+ a necessity - or - if it is already installed.
+
+ SAMPLE CODE
+ Please see DemoController.m from the HIDRemoteSample project for a reusable example on how to make best
+ use of this method in your code.
+*/
++ (BOOL)isCandelairInstallationRequiredForRemoteMode:(HIDRemoteMode)remoteMode;
+
+#pragma mark -- PUBLIC: Interface / API --
+/*
+ DESCRIPTION
+ Starts the HIDRemote in the respective mode kHIDRemoteModeShared, kHIDRemoteModeExclusive or
+ kHIDRemoteModeExclusiveAuto.
+
+ RESULT
+ YES, if setup was successful. NO, if an error occured during setup. Note that a successful setup
+ does not mean that you gained the respective level of access or that remote control hardware was
+ actually found. This is only the case if -activeRemoteControlCount returns a value
+ greater zero. I.e. your setup code could look like this:
+
+ if ((hidRemoteControl = [HIDRemoteControl sharedHIDRemote]) != nil)
+ {
+ [hidRemoteControl setDelegate:myDelegate];
+
+ if ([HIDRemote isCandelairInstallationRequiredForRemoteMode:kHIDRemoteModeExclusiveAuto])
+ {
+ NSLog(@"Installation of Candelair required."); // See DemoController.m for a reusable code snippet presenting an
+ // alert and offering to open related URLs
+ }
+ else
+ {
+ if ([hidRemoteControl startRemoteControl:kHIDRemoteModeExclusiveAuto])
+ {
+ NSLog(@"Driver has started successfully.");
+
+ if ([hidRemoteControl activeRemoteControlCount])
+ {
+ NSLog(@"Driver has found %d remotes.", [hidRemoteControl activeRemoteControlCount]);
+ }
+ else
+ {
+ NSLog(@"Driver has not found any remotes it could use. Will use remotes as they become available.");
+ }
+ }
+ else
+ {
+ // .. Setup failed ..
+ }
+ }
+ }
+*/
+- (BOOL)startRemoteControl:(HIDRemoteMode)hidRemoteMode;
+
+/*
+ DESCRIPTION
+ Stops the HIDRemote. You will no longer get remote control events after this. Other applications can
+ then access the remote again. To get a lock on the HIDRemote again, make use of -startRemoteControl:.
+*/
+- (void)stopRemoteControl;
+
+/*
+ DESCRIPTION
+ Determine, whether the HIDRemote has been started with -startRemoteControl:.
+
+ RESULT
+ YES, if it was started. NO, if it was not.
+*/
+- (BOOL)isStarted;
+
+/*
+ DESCRIPTION
+ Determine the number of remote controls HIDRemote has currently opened. This is usually 1 on current systems.
+*/
+- (unsigned)activeRemoteControlCount;
+
+/*
+ DESCRIPTION
+ Returns the ID of the remote from which the button press was received from last. You can sign up your delegate for
+ ID change notifications by implementing the (optional) -hidRemote:remoteIDChangedOldID:newID: selector.
+
+ RESULT
+ Returns the ID of the last seen remote. Returns -1, if the ID is unknown.
+*/
+- (SInt32)lastSeenRemoteControlID;
+
+/*
+ DESCRIPTION
+ Set a new delegate object. This object has to implement the HIDRemoteDelegate protocol. If it is also implementing
+ the optional HIDRemoteDelegate protocol methods, it will be able to receive additional notifications and events.
+
+ IMPORTANT
+ The delegate is not retained. Make sure you execute a -[hidRemoteInstance setDelegate:nil] in the dealloc method of
+ your delegate.
+*/
+- (void)setDelegate:(NSObject <HIDRemoteDelegate> *)newDelegate;
+
+/*
+ DESCRIPTION
+ Get the currently set delegate object.
+
+ RESULT
+ The currently set delegate object.
+*/
+- (NSObject <HIDRemoteDelegate> *)delegate;
+
+/*
+ DESCRIPTION
+ Set whether hold events should be simulated for the + and - buttons. The simulation is active by default. This value
+ should only be changed when no button is currently pressed (f.ex. before calling -startRemoteControl:). The behaviour
+ is undefined if a button press is currently in progress.
+*/
+- (void)setSimulateHoldEvents:(BOOL)newSimulateHoldEvents;
+
+/*
+ DESCRIPTION
+ Determine whether the simulation of hold events for the + and - buttons is currently active.
+
+ RESULT
+ YES or NO depending on whether the simulation is currently active.
+*/
+- (BOOL)simulateHoldEvents;
+
+/*
+ DESCRIPTION
+ Set an array of NSNumbers with HIDRemoteButtonCodes that are not used by your application. This is empty by default.
+ By providing this information, you improve interoperation with popular remote control solutions such as Remote Buddy.
+ If, for example, you don't use the MenuHold button code, you'd express it like this in your sourcecode:
+
+ if (hidRemote = [HIDRemote sharedHIDRemote])
+ {
+ // ..
+
+ [hidRemote setUnusedButtonCodes:[NSArray arrayWithObjects:[NSNumber numberWithInt:(int)kHIDRemoteButtonCodeMenuHold], nil]];
+
+ // ..
+ }
+
+ Advanced remote control solutions such as Remote Buddy do then know that you're not using the MenuHold button code and
+ can automatically create a mapping table for your application, with all buttons presses except MenuHold being forwarded
+ to your application. For MenuHold, Remote Buddy might map an action to open its own menu.
+*/
+- (void)setUnusedButtonCodes:(NSArray *)newArrayWithUnusedButtonCodesAsNSNumbers;
+
+/*
+ DESCRIPTION
+ Return an array of NSNumbers with HIDRemoteButtonCodes your application does not use. For more information, see the
+ description for -setUnusedButtonCodes:
+
+ RESULT
+ An array of NSNumbers with HIDRemoteButtonCodes your application does not use.
+*/
+- (NSArray *)unusedButtonCodes;
+
+#pragma mark -- PUBLIC: Expert APIs --
+
+/*
+ DESCRIPTION
+ Enables/disables a workaround to a locking issue introduced with Security Update 2008-004 / 10.4.9 and beyond. Essentially,
+ without this workaround enabled, using an application that uses a password textfield would degrade exclusive locks to shared
+ locks with the result being that both normal OS X as well as your application would react to the same HID event when really
+ only your application should. Credit for finding this workaround goes to Martin Kahr.
+
+ Enabled by default.
+*/
+- (void)setEnableSecureEventInputWorkaround:(BOOL)newEnableSecureEventInputWorkaround;
+
+/*
+ DESCRIPTION
+ Determine whether aforementioned workaround is active.
+
+ RESULT
+ YES or NO.
+*/
+- (BOOL)enableSecureEventInputWorkaround;
+
+/*
+ DESCRIPTION
+ Enables/disables lending of the exclusive lock to other applications when in kHIDRemoteModeExclusive mode.
+
+ Enable this option only when you are writing a background application that keeps a permanent, exclusive lock on the IR receiver.
+
+ When this option is enabled and another application using the HIDRemote class indicates that it'd like to get exclusive access
+ to the IR receiver itself while your application is having it, your application's instance of HIDRemote automatically stops and
+ signals the other application that it can now get exclusive access. When the other application's HIDRemote instance no longer uses
+ the IR receiver exclusively, it lets your application know so that it can recover its exclusive lock.
+
+ This option is disabled by default. Unless you have special needs, you really should use the kHIDRemoteModeExclusiveAuto mode for
+ best compatibility with other applications.
+*/
+- (void)setExclusiveLockLendingEnabled:(BOOL)newExclusiveLockLendingEnabled;
+- (BOOL)exclusiveLockLendingEnabled;
+
+#pragma mark -- PRIVATE: HID Event handling --
+- (void)_handleButtonCode:(HIDRemoteButtonCode)buttonCode isPressed:(BOOL)isPressed hidAttribsDict:(NSMutableDictionary *)hidAttribsDict;
+- (void)_sendButtonCode:(HIDRemoteButtonCode)buttonCode isPressed:(BOOL)isPressed;
+- (void)_hidEventFor:(io_service_t)hidDevice from:(IOHIDQueueInterface **)interface withResult:(IOReturn)result;
+
+#pragma mark -- PRIVATE: Service setup and destruction --
+- (BOOL)_prematchService:(io_object_t)service;
+- (BOOL)_setupService:(io_object_t)service;
+- (void)_destructService:(io_object_t)service;
+
+#pragma mark -- PRIVATE: Distributed notifiations handling --
+- (void)_postStatusWithAction:(NSString *)action;
+- (void)_handleNotifications:(NSNotification *)notification;
+
+#pragma mark -- PRIVATE: Application becomes active / inactive handling for kHIDRemoteModeExclusiveAuto --
+- (void)_appStatusChanged:(NSNotification *)notification;
+- (void)_delayedAutoRecovery:(NSTimer *)aTimer;
+
+#pragma mark -- PRIVATE: Notification handling --
+- (void)_serviceMatching:(io_iterator_t)iterator;
+- (void)_serviceNotificationFor:(io_service_t)service messageType:(natural_t)messageType messageArgument:(void *)messageArgument;
+
+@end
+
+#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) --
+extern NSString *kHIDRemoteCFPluginInterface;
+extern NSString *kHIDRemoteHIDDeviceInterface;
+extern NSString *kHIDRemoteCookieButtonCodeLUT;
+extern NSString *kHIDRemoteHIDQueueInterface;
+extern NSString *kHIDRemoteServiceNotification;
+extern NSString *kHIDRemoteCFRunLoopSource;
+extern NSString *kHIDRemoteLastButtonPressed;
+extern NSString *kHIDRemoteService;
+extern NSString *kHIDRemoteSimulateHoldEventsTimer;
+extern NSString *kHIDRemoteSimulateHoldEventsOriginButtonCode;
+
+#pragma mark -- Distributed notifications --
+extern NSString *kHIDRemoteDNHIDRemotePing;
+extern NSString *kHIDRemoteDNHIDRemoteRetry;
+extern NSString *kHIDRemoteDNHIDRemoteStatus;
+
+#pragma mark -- Distributed notifications userInfo keys and values --
+extern NSString *kHIDRemoteDNStatusHIDRemoteVersionKey;
+extern NSString *kHIDRemoteDNStatusPIDKey;
+extern NSString *kHIDRemoteDNStatusModeKey;
+extern NSString *kHIDRemoteDNStatusUnusedButtonCodesKey;
+extern NSString *kHIDRemoteDNStatusRemoteControlCountKey;
+extern NSString *kHIDRemoteDNStatusReturnToPIDKey;
+extern NSString *kHIDRemoteDNStatusActionKey;
+extern NSString *kHIDRemoteDNStatusActionStart;
+extern NSString *kHIDRemoteDNStatusActionStop;
+extern NSString *kHIDRemoteDNStatusActionUpdate;
+
+#pragma mark -- Driver compatibility flags --
+typedef enum
+{
+ kHIDRemoteCompatibilityFlagsStandardHIDRemoteDevice = 1L,
+} HIDRemoteCompatibilityFlags;
diff --git a/tools/EventClients/Clients/OSXRemote/HIDRemote.m b/tools/EventClients/Clients/OSXRemote/HIDRemote.m
new file mode 100644
index 0000000000..f8e9b9f953
--- /dev/null
+++ b/tools/EventClients/Clients/OSXRemote/HIDRemote.m
@@ -0,0 +1,1544 @@
+//
+// HIDRemote.m
+// HIDRemote V1.0
+//
+// Created by Felix Schwarz on 06.04.07.
+// Copyright 2007-2009 IOSPIRIT GmbH. All rights reserved.
+//
+// ** LICENSE *************************************************************************
+//
+// Copyright (c) 2007-2009 IOSPIRIT GmbH
+// 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
+// SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+// TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+// 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.
+//
+// ************************************************************************************
+
+#import "HIDRemote.h"
+
+// Callback Prototypes
+static void HIDEventCallback( void * target,
+ IOReturn result,
+ void * refcon,
+ void * sender);
+
+static void ServiceMatchingCallback( void *refCon,
+ io_iterator_t iterator);
+
+static void ServiceNotificationCallback(void * refCon,
+ io_service_t service,
+ natural_t messageType,
+ void * messageArgument);
+
+// Shared HIDRemote instance
+static HIDRemote *sHIDRemote = nil;
+
+@implementation HIDRemote
+
+#pragma mark -- Init, dealloc & shared instance --
+
++ (HIDRemote *)sharedHIDRemote
+{
+ if (!sHIDRemote)
+ {
+ sHIDRemote = [[HIDRemote alloc] init];
+ }
+
+ return (sHIDRemote);
+}
+
+- (id)init
+{
+ if (self = [super init])
+ {
+ // Detect application becoming active/inactive
+ [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_appStatusChanged:) name:NSApplicationDidBecomeActiveNotification object:[NSApplication sharedApplication]];
+ [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_appStatusChanged:) name:NSApplicationWillResignActiveNotification object:[NSApplication sharedApplication]];
+ [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_appStatusChanged:) name:NSApplicationWillTerminateNotification object:[NSApplication sharedApplication]];
+
+ // Handle distributed notifications
+ [[NSDistributedNotificationCenter defaultCenter] addObserver:self selector:@selector(_handleNotifications:) name:kHIDRemoteDNHIDRemotePing object:nil];
+ [[NSDistributedNotificationCenter defaultCenter] addObserver:self selector:@selector(_handleNotifications:) name:kHIDRemoteDNHIDRemoteRetry object:[NSString stringWithFormat:@"%d", getpid()]];
+
+ // 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
+ _secureEventInputWorkAround = YES;
+ _statusSecureEventInputWorkAroundEnabled = NO;
+
+ // Initialize instance variables
+ _lastSeenRemoteID = -1;
+ _unusedButtonCodes = [[NSMutableArray alloc] init];
+ _exclusiveLockLending = NO;
+ }
+
+ return (self);
+}
+
+- (void)dealloc
+{
+ [[NSNotificationCenter defaultCenter] removeObserver:self name:NSApplicationWillTerminateNotification object:[NSApplication sharedApplication]];
+ [[NSNotificationCenter defaultCenter] removeObserver:self name:NSApplicationWillResignActiveNotification object:[NSApplication sharedApplication]];
+ [[NSNotificationCenter defaultCenter] removeObserver:self name:NSApplicationDidBecomeActiveNotification object:[NSApplication sharedApplication]];
+
+ [[NSDistributedNotificationCenter defaultCenter] removeObserver:self name:kHIDRemoteDNHIDRemotePing object:nil];
+ [[NSDistributedNotificationCenter defaultCenter] removeObserver:self name:kHIDRemoteDNHIDRemoteRetry object:[NSString stringWithFormat:@"%d", getpid()]];
+
+ [self stopRemoteControl];
+
+ [self setExclusiveLockLendingEnabled:NO];
+
+ [self setDelegate:nil];
+
+ [_unusedButtonCodes release];
+ _unusedButtonCodes = nil;
+
+ [super dealloc];
+}
+
+#pragma mark -- PUBLIC: System Information --
++ (BOOL)isCandelairInstalled
+{
+ mach_port_t masterPort = 0;
+ kern_return_t kernResult;
+ io_service_t matchingService = 0;
+ BOOL isInstalled = NO;
+
+ kernResult = IOMasterPort(MACH_PORT_NULL, &masterPort);
+ if (kernResult || !masterPort) { return(NO); }
+
+ if ((matchingService = IOServiceGetMatchingService(masterPort, IOServiceMatching("IOSPIRITIRController"))) != 0)
+ {
+ isInstalled = YES;
+ IOObjectRelease((io_object_t) matchingService);
+ }
+
+ mach_port_deallocate(mach_task_self(), masterPort);
+
+ return (isInstalled);
+}
+
++ (BOOL)isCandelairInstallationRequiredForRemoteMode:(HIDRemoteMode)remoteMode
+{
+ SInt32 systemVersion = 0;
+
+ // Determine OS version
+ if (Gestalt(gestaltSystemVersion, &systemVersion) == noErr)
+ {
+ switch (systemVersion)
+ {
+ case 0x1060: // OS 10.6
+ case 0x1061: // OS 10.6.1
+ // 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)
+ {
+ case kHIDRemoteModeExclusive:
+ case kHIDRemoteModeExclusiveAuto:
+ if (![self isCandelairInstalled])
+ {
+ return (YES);
+ }
+ break;
+ }
+ break;
+ }
+ }
+
+ return (NO);
+}
+
+#pragma mark -- PUBLIC: Interface / API --
+- (BOOL)startRemoteControl:(HIDRemoteMode)hidRemoteMode
+{
+ if ((_mode == kHIDRemoteModeNone) && (hidRemoteMode != kHIDRemoteModeNone))
+ {
+ kern_return_t kernReturn;
+ CFMutableDictionaryRef matchDict=NULL;
+
+ // Work around a locking issue introduced with Security Update 2008-004 / 10.4.9 and beyond
+ if ((_mode != kHIDRemoteModeShared) && (_secureEventInputWorkAround))
+ {
+ if (!_statusSecureEventInputWorkAroundEnabled)
+ {
+ EnableSecureEventInput();
+
+ // Keep track of our use of EnableSecureEventInput()/DisableSecureEventInput() to avoid count "leaks"
+ _statusSecureEventInputWorkAroundEnabled = YES;
+ }
+ }
+
+ do
+ {
+ // Get IOKit master port
+ kernReturn = IOMasterPort(bootstrap_port, &_masterPort);
+ if ((kernReturn!=kIOReturnSuccess) || (_masterPort==0)) { break; }
+
+ // Setup notification port
+ _notifyPort = IONotificationPortCreate(_masterPort);
+
+ if (_notifyRLSource = IONotificationPortGetRunLoopSource(_notifyPort))
+ {
+ CFRunLoopAddSource( CFRunLoopGetCurrent(),
+ _notifyRLSource,
+ kCFRunLoopCommonModes);
+ }
+ else
+ {
+ break;
+ }
+
+ // Setup notification matching dict
+ matchDict = IOServiceMatching(kIOHIDDeviceKey);
+ CFRetain(matchDict);
+
+ // Actually add notification
+ kernReturn = IOServiceAddMatchingNotification( _notifyPort,
+ kIOFirstMatchNotification,
+ matchDict, // one reference count consumed by this call
+ ServiceMatchingCallback,
+ (void *) self,
+ &_matchingServicesIterator);
+ if (kernReturn != kIOReturnSuccess) { break; }
+
+ // Setup serviceAttribMap
+ _serviceAttribMap = [[NSMutableDictionary alloc] init];
+ if (!_serviceAttribMap) { break; }
+
+ // Phew .. everything went well!
+ _mode = hidRemoteMode;
+ CFRelease(matchDict);
+
+ [self _serviceMatching:_matchingServicesIterator];
+
+ [self _postStatusWithAction:kHIDRemoteDNStatusActionStart];
+
+ return (YES);
+
+ }while(0);
+
+ // An error occured. Do necessary clean up.
+ if (matchDict)
+ {
+ CFRelease(matchDict);
+ matchDict = NULL;
+ }
+
+ [self stopRemoteControl];
+ }
+
+ return (NO);
+}
+
+- (void)stopRemoteControl
+{
+ _autoRecover = NO;
+
+ if (_autoRecoveryTimer)
+ {
+ [_autoRecoveryTimer invalidate];
+ [_autoRecoveryTimer release];
+ _autoRecoveryTimer = nil;
+ }
+
+ if (_serviceAttribMap)
+ {
+ NSDictionary *cloneDict = [[NSDictionary alloc] initWithDictionary:_serviceAttribMap];
+
+ if (cloneDict)
+ {
+ NSEnumerator *mapKeyEnum = [cloneDict keyEnumerator];
+ NSNumber *serviceValue;
+
+ while (serviceValue = [mapKeyEnum nextObject])
+ {
+ [self _destructService:(io_object_t)[serviceValue unsignedIntValue]];
+ };
+
+ [cloneDict release];
+ cloneDict = nil;
+ }
+
+ [_serviceAttribMap release];
+ _serviceAttribMap = nil;
+ }
+
+ if (_matchingServicesIterator)
+ {
+ IOObjectRelease((io_object_t) _matchingServicesIterator);
+ _matchingServicesIterator = 0;
+ }
+
+ if (_notifyRLSource)
+ {
+ CFRunLoopSourceInvalidate(_notifyRLSource);
+
+ _notifyRLSource = NULL;
+ }
+
+ if (_notifyPort)
+ {
+ IONotificationPortDestroy(_notifyPort);
+ _notifyPort = NULL;
+ }
+
+ if (_masterPort)
+ {
+ mach_port_deallocate(mach_task_self(), _masterPort);
+ }
+
+ if (_statusSecureEventInputWorkAroundEnabled)
+ {
+ DisableSecureEventInput();
+ _statusSecureEventInputWorkAroundEnabled = NO;
+ }
+
+ [self _postStatusWithAction:kHIDRemoteDNStatusActionStop];
+
+ [_returnToPID release];
+ _returnToPID = nil;
+
+ _mode = kHIDRemoteModeNone;
+}
+
+- (BOOL)isStarted
+{
+ return (_mode != kHIDRemoteModeNone);
+}
+
+- (unsigned)activeRemoteControlCount
+{
+ return ([_serviceAttribMap count]);
+}
+
+- (SInt32)lastSeenRemoteControlID
+{
+ return (_lastSeenRemoteID);
+}
+
+- (void)setSimulateHoldEvents:(BOOL)newSimulateHoldEvents
+{
+ _simulateHoldEvents = newSimulateHoldEvents;
+}
+
+- (BOOL)simulateHoldEvents
+{
+ return (_simulateHoldEvents);
+}
+
+- (NSArray *)unusedButtonCodes
+{
+ return (_unusedButtonCodes);
+}
+
+- (void)setUnusedButtonCodes:(NSArray *)newArrayWithUnusedButtonCodesAsNSNumbers
+{
+ [newArrayWithUnusedButtonCodesAsNSNumbers retain];
+ [_unusedButtonCodes release];
+
+ _unusedButtonCodes = newArrayWithUnusedButtonCodesAsNSNumbers;
+
+ [self _postStatusWithAction:kHIDRemoteDNStatusActionUpdate];
+}
+
+- (void)setDelegate:(NSObject <HIDRemoteDelegate> *)newDelegate
+{
+ _delegate = newDelegate;
+}
+
+- (NSObject <HIDRemoteDelegate> *)delegate
+{
+ return (_delegate);
+}
+
+#pragma mark -- PUBLIC: Expert APIs --
+- (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
+{
+ return (_secureEventInputWorkAround);
+}
+
+- (void)setExclusiveLockLendingEnabled:(BOOL)newExclusiveLockLendingEnabled
+{
+ if (newExclusiveLockLendingEnabled != _exclusiveLockLending)
+ {
+ _exclusiveLockLending = newExclusiveLockLendingEnabled;
+
+ if (_exclusiveLockLending)
+ {
+ [[NSDistributedNotificationCenter defaultCenter] addObserver:self selector:@selector(_handleNotifications:) name:kHIDRemoteDNHIDRemoteStatus object:nil];
+ }
+ else
+ {
+ [[NSDistributedNotificationCenter defaultCenter] removeObserver:self name:kHIDRemoteDNHIDRemoteStatus object:nil];
+
+ [_waitForReturnByPID release];
+ _waitForReturnByPID = nil;
+ }
+ }
+}
+
+- (BOOL)exclusiveLockLendingEnabled
+{
+ return (_exclusiveLockLending);
+}
+
+#pragma mark -- PRIVATE: Application becomes active / inactive handling for kHIDRemoteModeExclusiveAuto --
+- (void)_appStatusChanged:(NSNotification *)notification
+{
+ if (notification)
+ {
+ if (_autoRecoveryTimer)
+ {
+ [_autoRecoveryTimer invalidate];
+ [_autoRecoveryTimer release];
+ _autoRecoveryTimer = nil;
+ }
+
+ if ([[notification name] isEqual:NSApplicationDidBecomeActiveNotification])
+ {
+ if (_autoRecover)
+ {
+ // Delay autorecover by 0.1 to avoid race conditions
+ if ((_autoRecoveryTimer = [[NSTimer alloc] initWithFireDate:[NSDate dateWithTimeIntervalSinceNow:0.1] interval:0.1 target:self selector:@selector(_delayedAutoRecovery:) userInfo:nil repeats:NO]) != nil)
+ {
+ // Using CFRunLoopAddTimer instead of [[NSRunLoop currentRunLoop] addTimer:.. for consistency with run loop modes.
+ // The kCFRunLoopCommonModes counterpart NSRunLoopCommonModes is only available in 10.5 and later, whereas this code
+ // is designed to be also compatible with 10.4. CFRunLoopTimerRef is "toll-free-bridged" with NSTimer since 10.0.
+ CFRunLoopAddTimer(CFRunLoopGetCurrent(), (CFRunLoopTimerRef)_autoRecoveryTimer, kCFRunLoopCommonModes);
+ }
+ }
+ }
+
+ if ([[notification name] isEqual:NSApplicationWillResignActiveNotification])
+ {
+ if (_mode == kHIDRemoteModeExclusiveAuto)
+ {
+ [self stopRemoteControl];
+ _autoRecover = YES;
+ }
+ }
+
+ if ([[notification name] isEqual:NSApplicationWillTerminateNotification])
+ {
+ if ([self isStarted])
+ {
+ [self stopRemoteControl];
+ }
+ }
+ }
+}
+
+- (void)_delayedAutoRecovery:(NSTimer *)aTimer
+{
+ [_autoRecoveryTimer invalidate];
+ [_autoRecoveryTimer release];
+ _autoRecoveryTimer = nil;
+
+ if (_autoRecover)
+ {
+ [self startRemoteControl:kHIDRemoteModeExclusiveAuto];
+ _autoRecover = NO;
+ }
+}
+
+
+#pragma mark -- PRIVATE: Distributed notifiations handling --
+- (void)_postStatusWithAction:(NSString *)action
+{
+ [[NSDistributedNotificationCenter defaultCenter] postNotificationName:kHIDRemoteDNHIDRemoteStatus
+ object:[NSString stringWithFormat:@"%d",getpid()]
+ userInfo:[NSDictionary dictionaryWithObjectsAndKeys:
+ [NSNumber numberWithInt:1], kHIDRemoteDNStatusHIDRemoteVersionKey,
+ [NSNumber numberWithUnsignedInt:(unsigned int)getpid()], kHIDRemoteDNStatusPIDKey,
+ [NSNumber numberWithInt:(int)_mode], kHIDRemoteDNStatusModeKey,
+ [NSNumber numberWithUnsignedInt:(unsigned int)[self activeRemoteControlCount]], kHIDRemoteDNStatusRemoteControlCountKey,
+ ((_unusedButtonCodes!=nil) ? _unusedButtonCodes : [NSArray array]), kHIDRemoteDNStatusUnusedButtonCodesKey,
+ action, kHIDRemoteDNStatusActionKey,
+ [[NSBundle mainBundle] bundleIdentifier], (NSString *)kCFBundleIdentifierKey,
+ _returnToPID, kHIDRemoteDNStatusReturnToPIDKey,
+ nil]
+ deliverImmediately:YES
+ ];
+}
+
+- (void)_handleNotifications:(NSNotification *)notification
+{
+ NSString *notificationName;
+
+ if ((notification!=nil) && ((notificationName = [notification name]) != nil))
+ {
+ if ([notificationName isEqual:kHIDRemoteDNHIDRemotePing])
+ {
+ [self _postStatusWithAction:kHIDRemoteDNStatusActionUpdate];
+ }
+
+ if ([notificationName isEqual:kHIDRemoteDNHIDRemoteRetry])
+ {
+ if ([self isStarted])
+ {
+ BOOL retry = YES;
+
+ if (([self delegate] != nil) &&
+ ([[self delegate] respondsToSelector:@selector(hidRemote:shouldRetryExclusiveLockWithInfo:)]))
+ {
+ retry = [[self delegate] hidRemote:self shouldRetryExclusiveLockWithInfo:[notification userInfo]];
+ }
+
+ if (retry)
+ {
+ HIDRemoteMode restartInMode = _mode;
+
+ if (restartInMode != kHIDRemoteModeNone)
+ {
+ [self stopRemoteControl];
+
+ [_returnToPID release];
+ [self startRemoteControl:restartInMode];
+
+ _returnToPID = [[[notification userInfo] objectForKey:kHIDRemoteDNStatusPIDKey] retain];
+ }
+ }
+ }
+ }
+
+ if (_exclusiveLockLending)
+ {
+ if ([notificationName isEqual:kHIDRemoteDNHIDRemoteStatus])
+ {
+ NSString *action;
+
+ if ((action = [[notification userInfo] objectForKey:kHIDRemoteDNStatusActionKey]) != nil)
+ {
+ if (_mode==kHIDRemoteModeExclusive)
+ {
+ if ([action isEqual:kHIDRemoteDNStatusActionStart])
+ {
+ NSNumber *originPID = [[notification userInfo] objectForKey:kHIDRemoteDNStatusPIDKey];
+
+ if ([originPID intValue] != getpid())
+ {
+ if (([self delegate] != nil) &&
+ ([[self delegate] respondsToSelector:@selector(hidRemote:lendExclusiveLockToApplicationWithInfo:)]))
+ {
+ if ([[self delegate] hidRemote:self lendExclusiveLockToApplicationWithInfo:[notification userInfo]])
+ {
+ [_waitForReturnByPID release];
+ _waitForReturnByPID = [originPID retain];
+
+ 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:
+ [NSNumber numberWithUnsignedInt:(unsigned int)getpid()], kHIDRemoteDNStatusPIDKey,
+ [[NSBundle mainBundle] bundleIdentifier], (NSString *)kCFBundleIdentifierKey,
+ nil]
+ deliverImmediately:YES];
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if ((_mode == kHIDRemoteModeNone) && _waitForReturnByPID)
+ {
+ if ([action isEqual:kHIDRemoteDNStatusActionStop])
+ {
+ NSNumber *pidNumber, *returnToPIDNumber;
+
+ if (((pidNumber = [[notification userInfo] objectForKey:kHIDRemoteDNStatusPIDKey]) != nil) &&
+ ((returnToPIDNumber = [[notification userInfo] objectForKey:kHIDRemoteDNStatusReturnToPIDKey]) != nil))
+ {
+ if ([pidNumber isEqual:_waitForReturnByPID] && ([returnToPIDNumber intValue] == getpid()))
+ {
+ [_waitForReturnByPID release];
+ _waitForReturnByPID = nil;
+
+ if (([self delegate] != nil) &&
+ ([[self delegate] respondsToSelector:@selector(hidRemote:exclusiveLockReleasedByApplicationWithInfo:)]))
+ {
+ [[self delegate] hidRemote:self exclusiveLockReleasedByApplicationWithInfo:[notification userInfo]];
+ }
+ else
+ {
+ [self startRemoteControl:kHIDRemoteModeExclusive];
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+#pragma mark -- PRIVATE: Service setup and destruction --
+- (BOOL)_prematchService:(io_object_t)service
+{
+ BOOL serviceMatches = NO;
+ NSString *ioClass;
+ NSNumber *candelairHIDRemoteCompatibilityMask;
+
+ if (service != 0)
+ {
+ // IOClass matching
+ if ((ioClass = (NSString *)IORegistryEntryCreateCFProperty((io_registry_entry_t)service,
+ CFSTR(kIOClassKey),
+ kCFAllocatorDefault,
+ 0)) != nil)
+ {
+ // Match on Apple's AppleIRController
+ if ([ioClass isEqual:@"AppleIRController"])
+ {
+ CFTypeRef candelairHIDRemoteCompatibilityDevice;
+
+ serviceMatches = YES;
+
+ if ((candelairHIDRemoteCompatibilityDevice = IORegistryEntryCreateCFProperty((io_registry_entry_t)service, CFSTR("CandelairHIDRemoteCompatibilityDevice"), kCFAllocatorDefault, 0)) != NULL)
+ {
+ if (CFEqual(kCFBooleanTrue, candelairHIDRemoteCompatibilityDevice))
+ {
+ serviceMatches = NO;
+ }
+
+ CFRelease (candelairHIDRemoteCompatibilityDevice);
+ }
+ }
+
+ // Match on the virtual IOSPIRIT IR Controller
+ if ([ioClass isEqual:@"IOSPIRITIRController"])
+ {
+ serviceMatches = YES;
+ }
+
+ CFRelease((CFTypeRef)ioClass);
+ }
+
+ // Match on services that claim compatibility with the HID Remote class (Candelair or third-party) by having a property of CandelairHIDRemoteCompatibilityMask = 1 <Type: Number>
+ if ((candelairHIDRemoteCompatibilityMask = (NSNumber *)IORegistryEntryCreateCFProperty((io_registry_entry_t)service, CFSTR("CandelairHIDRemoteCompatibilityMask"), kCFAllocatorDefault, 0)) != nil)
+ {
+ if ([candelairHIDRemoteCompatibilityMask isKindOfClass:[NSNumber class]])
+ {
+ if ([candelairHIDRemoteCompatibilityMask unsignedIntValue] & kHIDRemoteCompatibilityFlagsStandardHIDRemoteDevice)
+ {
+ serviceMatches = YES;
+ }
+ else
+ {
+ serviceMatches = NO;
+ }
+ }
+
+ CFRelease((CFTypeRef)candelairHIDRemoteCompatibilityMask);
+ }
+ }
+
+ if (([self delegate]!=nil) &&
+ ([[self delegate] respondsToSelector:@selector(hidRemote:inspectNewHardwareWithService:prematchResult:)]))
+ {
+ serviceMatches = [((NSObject <HIDRemoteDelegate> *)[self delegate]) hidRemote:self inspectNewHardwareWithService:service prematchResult:serviceMatches];
+ }
+
+ return (serviceMatches);
+}
+
+- (BOOL)_setupService:(io_object_t)service
+{
+ kern_return_t kernResult;
+ IOReturn returnCode;
+ HRESULT hResult;
+ SInt32 score;
+ BOOL opened = NO, queueStarted = NO;
+ IOHIDDeviceInterface122 **hidDeviceInterface = NULL;
+ IOCFPlugInInterface **cfPluginInterface = NULL;
+ IOHIDQueueInterface **hidQueueInterface = NULL;
+ io_object_t serviceNotification = 0;
+ CFRunLoopSourceRef queueEventSource = NULL;
+ NSMutableDictionary *hidAttribsDict = nil;
+ CFArrayRef hidElements = NULL;
+ NSError *error = nil;
+ UInt32 errorCode = 0;
+
+ if (![self _prematchService:service])
+ {
+ return (NO);
+ }
+
+ do
+ {
+ // Create a plugin interface ..
+ kernResult = IOCreatePlugInInterfaceForService( service,
+ kIOHIDDeviceUserClientTypeID,
+ kIOCFPlugInInterfaceID,
+ &cfPluginInterface,
+ &score);
+
+ if (kernResult != kIOReturnSuccess)
+ {
+ error = [NSError errorWithDomain:NSMachErrorDomain code:kernResult userInfo:nil];
+ errorCode = 1;
+ break;
+ }
+
+
+ // .. use it to get the HID interface ..
+ hResult = (*cfPluginInterface)->QueryInterface( cfPluginInterface,
+ CFUUIDGetUUIDBytes(kIOHIDDeviceInterfaceID122),
+ (LPVOID)&hidDeviceInterface);
+
+ if ((hResult!=S_OK) || (hidDeviceInterface==NULL))
+ {
+ error = [NSError errorWithDomain:NSMachErrorDomain code:hResult userInfo:nil];
+ errorCode = 2;
+ break;
+ }
+
+
+ // .. then open it ..
+ switch (_mode)
+ {
+ case kHIDRemoteModeShared:
+ hResult = (*hidDeviceInterface)->open(hidDeviceInterface, kIOHIDOptionsTypeNone);
+ break;
+
+ case kHIDRemoteModeExclusive:
+ case kHIDRemoteModeExclusiveAuto:
+ hResult = (*hidDeviceInterface)->open(hidDeviceInterface, kIOHIDOptionsTypeSeizeDevice);
+ break;
+
+ default:
+ goto cleanUp; // Ugh! But there are no "double breaks" available in C AFAIK ..
+ break;
+ }
+
+ if (hResult!=S_OK)
+ {
+ error = [NSError errorWithDomain:NSMachErrorDomain code:hResult userInfo:nil];
+ errorCode = 3;
+ break;
+ }
+
+ opened = YES;
+
+ // .. query the HID elements ..
+ returnCode = (*hidDeviceInterface)->copyMatchingElements(hidDeviceInterface,
+ NULL,
+ &hidElements);
+ if ((returnCode != kIOReturnSuccess) || (hidElements==NULL))
+ {
+ error = [NSError errorWithDomain:NSMachErrorDomain code:returnCode userInfo:nil];
+ errorCode = 4;
+
+ break;
+ }
+
+ // Setup an event queue for HID events!
+ hidQueueInterface = (*hidDeviceInterface)->allocQueue(hidDeviceInterface);
+ if (hidQueueInterface == NULL)
+ {
+ error = [NSError errorWithDomain:NSMachErrorDomain code:kIOReturnError userInfo:nil];
+ errorCode = 5;
+
+ break;
+ }
+
+ returnCode = (*hidQueueInterface)->create(hidQueueInterface, 0, 32);
+ if ((returnCode != kIOReturnSuccess) || (hidElements==NULL))
+ {
+ error = [NSError errorWithDomain:NSMachErrorDomain code:returnCode userInfo:nil];
+ errorCode = 6;
+
+ break;
+ }
+
+
+ // Setup of attributes stored for this HID device
+ hidAttribsDict = [[NSMutableDictionary alloc] initWithObjectsAndKeys:
+ [NSValue valueWithPointer:(const void *)cfPluginInterface], kHIDRemoteCFPluginInterface,
+ [NSValue valueWithPointer:(const void *)hidDeviceInterface], kHIDRemoteHIDDeviceInterface,
+ [NSValue valueWithPointer:(const void *)hidQueueInterface], kHIDRemoteHIDQueueInterface,
+ nil];
+
+ {
+ UInt32 i, hidElementCnt = 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;
+
+ error = [NSError errorWithDomain:NSMachErrorDomain code:kIOReturnError userInfo:nil];
+ errorCode = 7;
+
+ break;
+ }
+
+ // Analyze the HID elements and find matching elements
+ for (i=0;i<hidElementCnt;i++)
+ {
+ CFDictionaryRef hidDict;
+ NSNumber *usage, *usagePage, *cookie;
+ HIDRemoteButtonCode buttonCode = kHIDRemoteButtonCodeNone;
+
+ hidDict = CFArrayGetValueAtIndex(hidElements, i);
+
+ usage = (NSNumber *) CFDictionaryGetValue(hidDict, CFSTR(kIOHIDElementUsageKey));
+ usagePage = (NSNumber *) CFDictionaryGetValue(hidDict, CFSTR(kIOHIDElementUsagePageKey));
+ cookie = (NSNumber *) CFDictionaryGetValue(hidDict, CFSTR(kIOHIDElementCookieKey));
+
+ 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;
+ }
+
+ // Did record match?
+ if (buttonCode != kHIDRemoteButtonCodeNone)
+ {
+ NSString *pairString = [[NSString alloc] initWithFormat:@"%u_%u", [usagePage unsignedIntValue], [usage unsignedIntValue]];
+ NSNumber *buttonCodeNumber = [[NSNumber alloc] initWithUnsignedInt:(unsigned int)buttonCode];
+
+ [cookieCount setObject:buttonCodeNumber forKey:pairString];
+ [cookieButtonCodeLUT setObject:buttonCodeNumber forKey:cookie];
+
+ (*hidQueueInterface)->addElement(hidQueueInterface,
+ (IOHIDElementCookie) [cookie unsignedIntValue],
+ 0);
+
+ [buttonCodeNumber release];
+ [pairString release];
+ }
+ }
+ }
+
+ // Compare number of *unique* matches (thus the cookieCount dictionary) with required minimum
+ if ([cookieCount count] < 10)
+ {
+ [cookieButtonCodeLUT release];
+ cookieButtonCodeLUT = nil;
+
+ [cookieCount release];
+ cookieCount = nil;
+
+ error = [NSError errorWithDomain:NSMachErrorDomain code:kIOReturnError userInfo:nil];
+ errorCode = 8;
+
+ break;
+ }
+
+ [hidAttribsDict setObject:cookieButtonCodeLUT forKey:kHIDRemoteCookieButtonCodeLUT];
+
+ [cookieButtonCodeLUT release];
+ cookieButtonCodeLUT = nil;
+
+ [cookieCount release];
+ cookieCount = nil;
+ }
+
+ // Finish setup of IOHIDQueueInterface with CFRunLoop
+ returnCode = (*hidQueueInterface)->createAsyncEventSource(hidQueueInterface, &queueEventSource);
+ if ((returnCode != kIOReturnSuccess) || (queueEventSource == NULL))
+ {
+ error = [NSError errorWithDomain:NSMachErrorDomain code:returnCode userInfo:nil];
+ errorCode = 9;
+ break;
+ }
+
+ returnCode = (*hidQueueInterface)->setEventCallout(hidQueueInterface, HIDEventCallback, (void *)((intptr_t)service), (void *)self);
+ if (returnCode != kIOReturnSuccess)
+ {
+ error = [NSError errorWithDomain:NSMachErrorDomain code:returnCode userInfo:nil];
+ errorCode = 10;
+ break;
+ }
+
+ CFRunLoopAddSource( CFRunLoopGetCurrent(),
+ queueEventSource,
+ kCFRunLoopCommonModes);
+ [hidAttribsDict setObject:[NSValue valueWithPointer:(const void *)queueEventSource] forKey:kHIDRemoteCFRunLoopSource];
+
+ returnCode = (*hidQueueInterface)->start(hidQueueInterface);
+ if (returnCode != kIOReturnSuccess)
+ {
+ error = [NSError errorWithDomain:NSMachErrorDomain code:returnCode userInfo:nil];
+ errorCode = 11;
+ break;
+ }
+
+ queueStarted = YES;
+
+ // Setup device notifications
+ returnCode = IOServiceAddInterestNotification( _notifyPort,
+ service,
+ kIOGeneralInterest,
+ ServiceNotificationCallback,
+ self,
+ &serviceNotification);
+ if ((returnCode != kIOReturnSuccess) || (serviceNotification==0))
+ {
+ error = [NSError errorWithDomain:NSMachErrorDomain code:returnCode userInfo:nil];
+ errorCode = 12;
+ break;
+ }
+
+ [hidAttribsDict setObject:[NSNumber numberWithUnsignedInt:(unsigned int)serviceNotification] forKey:kHIDRemoteServiceNotification];
+
+ // Retain service
+ if (IOObjectRetain(service) != kIOReturnSuccess)
+ {
+ error = [NSError errorWithDomain:NSMachErrorDomain code:kIOReturnError userInfo:nil];
+ errorCode = 13;
+ break;
+ }
+
+ [hidAttribsDict setObject:[NSNumber numberWithUnsignedInt:(unsigned int)service] forKey:kHIDRemoteService];
+
+ // Get some (somewhat optional) infos on the device
+ {
+ CFStringRef product, manufacturer, transport;
+
+ if ((product = IORegistryEntryCreateCFProperty( (io_registry_entry_t)service,
+ (CFStringRef) @"Product",
+ kCFAllocatorDefault,
+ 0)) != NULL)
+ {
+ if (CFGetTypeID(product) == CFStringGetTypeID())
+ {
+ [hidAttribsDict setObject:(NSString *)product forKey:kHIDRemoteProduct];
+ }
+
+ CFRelease(product);
+ }
+
+ if ((manufacturer = IORegistryEntryCreateCFProperty( (io_registry_entry_t)service,
+ (CFStringRef) @"Manufacturer",
+ kCFAllocatorDefault,
+ 0)) != NULL)
+ {
+ if (CFGetTypeID(manufacturer) == CFStringGetTypeID())
+ {
+ [hidAttribsDict setObject:(NSString *)manufacturer forKey:kHIDRemoteManufacturer];
+ }
+
+ CFRelease(manufacturer);
+ }
+
+ if ((transport = IORegistryEntryCreateCFProperty( (io_registry_entry_t)service,
+ (CFStringRef) @"Transport",
+ kCFAllocatorDefault,
+ 0)) != NULL)
+ {
+ if (CFGetTypeID(transport) == CFStringGetTypeID())
+ {
+ [hidAttribsDict setObject:(NSString *)transport forKey:kHIDRemoteTransport];
+ }
+
+ CFRelease(transport);
+ }
+ }
+
+ // Add it to the serviceAttribMap
+ [_serviceAttribMap setObject:hidAttribsDict forKey:[NSNumber numberWithUnsignedInt:(unsigned int)service]];
+
+ // And we're done with setup ..
+ if (([self delegate]!=nil) &&
+ ([[self delegate] respondsToSelector:@selector(hidRemote:foundNewHardwareWithAttributes:)]))
+ {
+ [((NSObject <HIDRemoteDelegate> *)[self delegate]) hidRemote:self foundNewHardwareWithAttributes:hidAttribsDict];
+ }
+
+ [hidAttribsDict release];
+ hidAttribsDict = nil;
+
+ return(YES);
+
+ }while(0);
+
+ cleanUp:
+
+ if (([self delegate]!=nil) &&
+ ([[self delegate] respondsToSelector:@selector(hidRemote:failedNewHardwareWithError:)]))
+ {
+ if (error)
+ {
+ error = [NSError errorWithDomain:[error domain]
+ code:[error code]
+ userInfo:[NSDictionary dictionaryWithObject:[NSNumber numberWithInt:errorCode] forKey:@"InternalErrorCode"]
+ ];
+ }
+
+ [((NSObject <HIDRemoteDelegate> *)[self delegate]) hidRemote:self failedNewHardwareWithError:error];
+ }
+
+ // An error occured or this device is not of interest .. cleanup ..
+ if (serviceNotification)
+ {
+ IOObjectRelease(serviceNotification);
+ serviceNotification = 0;
+ }
+
+ if (queueEventSource)
+ {
+ CFRunLoopSourceInvalidate(queueEventSource);
+ queueEventSource=NULL;
+ }
+
+ if (hidQueueInterface)
+ {
+ if (queueStarted)
+ {
+ (*hidQueueInterface)->stop(hidQueueInterface);
+ }
+ (*hidQueueInterface)->dispose(hidQueueInterface);
+ (*hidQueueInterface)->Release(hidQueueInterface);
+ hidQueueInterface = NULL;
+ }
+
+ if (hidAttribsDict)
+ {
+ [hidAttribsDict release];
+ hidAttribsDict = nil;
+ }
+
+ if (hidElements)
+ {
+ CFRelease(hidElements);
+ hidElements = NULL;
+ }
+
+ if (hidDeviceInterface)
+ {
+ if (opened)
+ {
+ (*hidDeviceInterface)->close(hidDeviceInterface);
+ }
+ (*hidDeviceInterface)->Release(hidDeviceInterface);
+ // opened = NO;
+ hidDeviceInterface = NULL;
+ }
+
+ if (cfPluginInterface)
+ {
+ IODestroyPlugInInterface(cfPluginInterface);
+ cfPluginInterface = NULL;
+ }
+
+ return (NO);
+}
+
+- (void)_destructService:(io_object_t)service
+{
+ NSNumber *serviceValue;
+ NSMutableDictionary *serviceDict = NULL;
+
+ if ((serviceValue = [NSNumber numberWithUnsignedInt:(unsigned int)service]) == nil)
+ {
+ return;
+ }
+
+ serviceDict = [_serviceAttribMap objectForKey:serviceValue];
+
+ if (serviceDict)
+ {
+ IOHIDDeviceInterface122 **hidDeviceInterface = NULL;
+ IOCFPlugInInterface **cfPluginInterface = NULL;
+ IOHIDQueueInterface **hidQueueInterface = NULL;
+ io_object_t serviceNotification = 0;
+ CFRunLoopSourceRef queueEventSource = NULL;
+ io_object_t theService = 0;
+ NSMutableDictionary *cookieButtonMap = nil;
+ NSTimer *simulateHoldTimer = nil;
+
+ serviceNotification = (io_object_t) ([serviceDict objectForKey:kHIDRemoteServiceNotification] ? [[serviceDict objectForKey:kHIDRemoteServiceNotification] unsignedIntValue] : 0);
+ theService = (io_object_t) ([serviceDict objectForKey:kHIDRemoteService] ? [[serviceDict objectForKey:kHIDRemoteService] unsignedIntValue] : 0);
+ queueEventSource = (CFRunLoopSourceRef) ([serviceDict objectForKey:kHIDRemoteCFRunLoopSource] ? [[serviceDict objectForKey:kHIDRemoteCFRunLoopSource] pointerValue] : NULL);
+ hidQueueInterface = (IOHIDQueueInterface **) ([serviceDict objectForKey:kHIDRemoteHIDQueueInterface] ? [[serviceDict objectForKey:kHIDRemoteHIDQueueInterface] pointerValue] : NULL);
+ hidDeviceInterface = (IOHIDDeviceInterface122 **) ([serviceDict objectForKey:kHIDRemoteHIDDeviceInterface] ? [[serviceDict objectForKey:kHIDRemoteHIDDeviceInterface] pointerValue] : NULL);
+ cfPluginInterface = (IOCFPlugInInterface **) ([serviceDict objectForKey:kHIDRemoteCFPluginInterface] ? [[serviceDict objectForKey:kHIDRemoteCFPluginInterface] pointerValue] : NULL);
+ cookieButtonMap = (NSMutableDictionary *) [serviceDict objectForKey:kHIDRemoteCookieButtonCodeLUT];
+ simulateHoldTimer = (NSTimer *) [serviceDict objectForKey:kHIDRemoteSimulateHoldEventsTimer];
+
+ [serviceDict retain];
+ [_serviceAttribMap removeObjectForKey:serviceValue];
+
+ if (([self delegate]!=nil) &&
+ ([[self delegate] respondsToSelector:@selector(hidRemote:releasedHardwareWithAttributes:)]))
+ {
+ [((NSObject <HIDRemoteDelegate> *)[self delegate]) hidRemote:self releasedHardwareWithAttributes:serviceDict];
+ }
+
+ if (simulateHoldTimer)
+ {
+ [simulateHoldTimer invalidate];
+ }
+
+ if (serviceNotification)
+ {
+ IOObjectRelease(serviceNotification);
+ }
+
+ if (queueEventSource)
+ {
+ CFRunLoopRemoveSource( CFRunLoopGetCurrent(),
+ queueEventSource,
+ kCFRunLoopCommonModes);
+ }
+
+ if (hidQueueInterface && cookieButtonMap)
+ {
+ NSEnumerator *cookieEnum = [cookieButtonMap keyEnumerator];
+ NSNumber *cookie;
+
+ while (cookie = [cookieEnum nextObject])
+ {
+ if ((*hidQueueInterface)->hasElement(hidQueueInterface, (IOHIDElementCookie) [cookie unsignedIntValue]))
+ {
+ (*hidQueueInterface)->removeElement(hidQueueInterface,
+ (IOHIDElementCookie) [cookie unsignedIntValue]);
+ }
+ };
+ }
+
+ if (hidQueueInterface)
+ {
+ (*hidQueueInterface)->stop(hidQueueInterface);
+ (*hidQueueInterface)->dispose(hidQueueInterface);
+ (*hidQueueInterface)->Release(hidQueueInterface);
+ }
+
+ if (hidDeviceInterface)
+ {
+ (*hidDeviceInterface)->close(hidDeviceInterface);
+ (*hidDeviceInterface)->Release(hidDeviceInterface);
+ }
+
+ if (cfPluginInterface)
+ {
+ IODestroyPlugInInterface(cfPluginInterface);
+ }
+
+ if (theService)
+ {
+ IOObjectRelease(theService);
+ }
+
+ [serviceDict release];
+ }
+}
+
+
+#pragma mark -- PRIVATE: HID Event handling --
+- (void)_simulateHoldEvent:(NSTimer *)aTimer
+{
+ NSMutableDictionary *hidAttribsDict;
+ NSTimer *shTimer;
+ NSNumber *shButtonCode;
+
+ if ((hidAttribsDict = (NSMutableDictionary *)[aTimer userInfo]) != nil)
+ {
+ if (((shTimer = [hidAttribsDict objectForKey:kHIDRemoteSimulateHoldEventsTimer]) != nil) &&
+ ((shButtonCode = [hidAttribsDict objectForKey:kHIDRemoteSimulateHoldEventsOriginButtonCode]) != nil))
+ {
+ [shTimer invalidate];
+ [hidAttribsDict removeObjectForKey:kHIDRemoteSimulateHoldEventsTimer];
+
+ [self _sendButtonCode:(((HIDRemoteButtonCode)[shButtonCode unsignedIntValue])|kHIDRemoteButtonCodeHoldMask) isPressed:YES];
+ }
+ }
+}
+
+- (void)_handleButtonCode:(HIDRemoteButtonCode)buttonCode isPressed:(BOOL)isPressed hidAttribsDict:(NSMutableDictionary *)hidAttribsDict
+{
+ switch (buttonCode)
+ {
+ case kHIDRemoteButtonCodeIDChanged:
+ // Do nothing, this is handled seperately
+ break;
+
+ case kHIDRemoteButtonCodePlus:
+ case kHIDRemoteButtonCodeMinus:
+ if (_simulateHoldEvents)
+ {
+ NSTimer *shTimer = nil;
+ NSNumber *shButtonCode = nil;
+
+ [[hidAttribsDict objectForKey:kHIDRemoteSimulateHoldEventsTimer] invalidate];
+
+ if (isPressed)
+ {
+ [hidAttribsDict setObject:[NSNumber numberWithUnsignedInt:buttonCode] forKey:kHIDRemoteSimulateHoldEventsOriginButtonCode];
+
+ if ((shTimer = [[NSTimer alloc] initWithFireDate:[NSDate dateWithTimeIntervalSinceNow:0.7] interval:0.1 target:self selector:@selector(_simulateHoldEvent:) userInfo:hidAttribsDict repeats:NO]) != nil)
+ {
+ [hidAttribsDict setObject:shTimer forKey:kHIDRemoteSimulateHoldEventsTimer];
+
+ // Using CFRunLoopAddTimer instead of [[NSRunLoop currentRunLoop] addTimer:.. for consistency with run loop modes.
+ // The kCFRunLoopCommonModes counterpart NSRunLoopCommonModes is only available in 10.5 and later, whereas this code
+ // 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];
+
+ break;
+ }
+ }
+ else
+ {
+ shTimer = [hidAttribsDict objectForKey:kHIDRemoteSimulateHoldEventsTimer];
+ shButtonCode = [hidAttribsDict objectForKey:kHIDRemoteSimulateHoldEventsOriginButtonCode];
+
+ if (shTimer && shButtonCode)
+ {
+ [self _sendButtonCode:(HIDRemoteButtonCode)[shButtonCode unsignedIntValue] isPressed:YES];
+ [self _sendButtonCode:(HIDRemoteButtonCode)[shButtonCode unsignedIntValue] isPressed:NO];
+ }
+ else
+ {
+ if (shButtonCode)
+ {
+ [self _sendButtonCode:(((HIDRemoteButtonCode)[shButtonCode unsignedIntValue])|kHIDRemoteButtonCodeHoldMask) isPressed:NO];
+ }
+ }
+ }
+
+ [hidAttribsDict removeObjectForKey:kHIDRemoteSimulateHoldEventsTimer];
+ [hidAttribsDict removeObjectForKey:kHIDRemoteSimulateHoldEventsOriginButtonCode];
+
+ break;
+ }
+
+ default:
+ [self _sendButtonCode:buttonCode isPressed:isPressed];
+ break;
+ }
+}
+
+- (void)_sendButtonCode:(HIDRemoteButtonCode)buttonCode isPressed:(BOOL)isPressed
+{
+ if (([self delegate]!=nil) &&
+ ([[self delegate] respondsToSelector:@selector(hidRemote:eventWithButton:isPressed:)]))
+ {
+ [((NSObject <HIDRemoteDelegate> *)[self delegate]) hidRemote:self eventWithButton:buttonCode isPressed:isPressed];
+ }
+}
+
+- (void)_hidEventFor:(io_service_t)hidDevice from:(IOHIDQueueInterface **)interface withResult:(IOReturn)result
+{
+ NSMutableDictionary *hidAttribsDict = [_serviceAttribMap objectForKey:[NSNumber numberWithUnsignedInt:(unsigned int)hidDevice]];
+
+ if (hidAttribsDict)
+ {
+ IOHIDQueueInterface **queueInterface = NULL;
+
+ queueInterface = [[hidAttribsDict objectForKey:kHIDRemoteHIDQueueInterface] pointerValue];
+
+ if (interface == queueInterface)
+ {
+ NSNumber *lastButtonPressedNumber = nil;
+ HIDRemoteButtonCode lastButtonPressed = kHIDRemoteButtonCodeNone;
+ NSMutableDictionary *cookieButtonMap = nil;
+
+ cookieButtonMap = [hidAttribsDict objectForKey:kHIDRemoteCookieButtonCodeLUT];
+
+ if ((lastButtonPressedNumber = [hidAttribsDict objectForKey:kHIDRemoteLastButtonPressed]) != nil)
+ {
+ lastButtonPressed = [lastButtonPressedNumber unsignedIntValue];
+ }
+
+ while (result == kIOReturnSuccess)
+ {
+ IOHIDEventStruct hidEvent;
+ AbsoluteTime supportedTime = { 0,0 };
+
+ result = (*queueInterface)->getNextEvent( queueInterface,
+ &hidEvent,
+ supportedTime,
+ 0);
+
+ if (result == kIOReturnSuccess)
+ {
+ NSNumber *buttonCodeNumber = [cookieButtonMap objectForKey:[NSNumber numberWithUnsignedInt:(unsigned int) hidEvent.elementCookie]];
+
+ if (buttonCodeNumber)
+ {
+ HIDRemoteButtonCode buttonCode = [buttonCodeNumber unsignedIntValue];
+
+ if (hidEvent.value == 0)
+ {
+ if (buttonCode == lastButtonPressed)
+ {
+ [self _handleButtonCode:lastButtonPressed isPressed:NO hidAttribsDict:hidAttribsDict];
+ lastButtonPressed = kHIDRemoteButtonCodeNone;
+ }
+ }
+
+ if (hidEvent.value != 0)
+ {
+ if (lastButtonPressed != kHIDRemoteButtonCodeNone)
+ {
+ [self _handleButtonCode:lastButtonPressed isPressed:NO hidAttribsDict:hidAttribsDict];
+ // lastButtonPressed = kHIDRemoteButtonCodeNone;
+ }
+
+ if (buttonCode == kHIDRemoteButtonCodeIDChanged)
+ {
+ if (([self delegate]!=nil) &&
+ ([[self delegate] respondsToSelector:@selector(hidRemote:remoteIDChangedOldID:newID:)]))
+ {
+ [((NSObject <HIDRemoteDelegate> *)[self delegate]) hidRemote:self remoteIDChangedOldID:_lastSeenRemoteID newID:hidEvent.value];
+ }
+
+ _lastSeenRemoteID = hidEvent.value;
+ }
+
+ [self _handleButtonCode:buttonCode isPressed:YES hidAttribsDict:hidAttribsDict];
+ lastButtonPressed = buttonCode;
+ }
+ }
+ }
+ };
+
+ [hidAttribsDict setObject:[NSNumber numberWithUnsignedInt:lastButtonPressed] forKey:kHIDRemoteLastButtonPressed];
+ }
+ }
+}
+
+#pragma mark -- PRIVATE: Notification handling --
+- (void)_serviceMatching:(io_iterator_t)iterator
+{
+ io_object_t matchingService = 0;
+
+ while (matchingService = IOIteratorNext(iterator))
+ {
+ [self _setupService:matchingService];
+
+ IOObjectRelease(matchingService);
+ };
+}
+
+- (void)_serviceNotificationFor:(io_service_t)service messageType:(natural_t)messageType messageArgument:(void *)messageArgument
+{
+ if (messageType == kIOMessageServiceIsTerminated)
+ {
+ [self _destructService:service];
+ }
+}
+
+@end
+
+#pragma mark -- PRIVATE: IOKitLib Callbacks --
+
+static void HIDEventCallback( void * target,
+ IOReturn result,
+ void * refCon,
+ void * sender)
+{
+ HIDRemote *hidRemote = (HIDRemote *)refCon;
+ NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
+
+ [hidRemote _hidEventFor:(io_service_t)((intptr_t)target) from:(IOHIDQueueInterface**)sender withResult:(IOReturn)result];
+
+ [pool release];
+}
+
+
+static void ServiceMatchingCallback( void *refCon,
+ io_iterator_t iterator)
+{
+ HIDRemote *hidRemote = (HIDRemote *)refCon;
+ NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
+
+ [hidRemote _serviceMatching:iterator];
+
+ [pool release];
+}
+
+static void ServiceNotificationCallback(void * refCon,
+ io_service_t service,
+ natural_t messageType,
+ void * messageArgument)
+{
+ HIDRemote *hidRemote = (HIDRemote *)refCon;
+ NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
+
+ [hidRemote _serviceNotificationFor:service
+ messageType:messageType
+ messageArgument:messageArgument];
+
+ [pool release];
+}
+
+// Attribute dictionary keys
+NSString *kHIDRemoteCFPluginInterface = @"CFPluginInterface";
+NSString *kHIDRemoteHIDDeviceInterface = @"HIDDeviceInterface";
+NSString *kHIDRemoteCookieButtonCodeLUT = @"CookieButtonCodeLUT";
+NSString *kHIDRemoteHIDQueueInterface = @"HIDQueueInterface";
+NSString *kHIDRemoteServiceNotification = @"ServiceNotification";
+NSString *kHIDRemoteCFRunLoopSource = @"CFRunLoopSource";
+NSString *kHIDRemoteLastButtonPressed = @"LastButtonPressed";
+NSString *kHIDRemoteService = @"Service";
+NSString *kHIDRemoteSimulateHoldEventsTimer = @"SimulateHoldEventsTimer";
+NSString *kHIDRemoteSimulateHoldEventsOriginButtonCode = @"SimulateHoldEventsOriginButtonCode";
+
+NSString *kHIDRemoteManufacturer = @"Manufacturer";
+NSString *kHIDRemoteProduct = @"Product";
+NSString *kHIDRemoteTransport = @"Transport";
+
+// Distributed notifications
+NSString *kHIDRemoteDNHIDRemotePing = @"com.candelair.ping";
+NSString *kHIDRemoteDNHIDRemoteRetry = @"com.candelair.retry";
+NSString *kHIDRemoteDNHIDRemoteStatus = @"com.candelair.status";
+
+// Distributed notifications userInfo keys and values
+NSString *kHIDRemoteDNStatusHIDRemoteVersionKey = @"HIDRemoteVersion";
+NSString *kHIDRemoteDNStatusPIDKey = @"PID";
+NSString *kHIDRemoteDNStatusModeKey = @"Mode";
+NSString *kHIDRemoteDNStatusUnusedButtonCodesKey = @"UnusedButtonCodes";
+NSString *kHIDRemoteDNStatusActionKey = @"Action";
+NSString *kHIDRemoteDNStatusRemoteControlCountKey = @"RemoteControlCount";
+NSString *kHIDRemoteDNStatusReturnToPIDKey = @"ReturnToPID";
+NSString *kHIDRemoteDNStatusActionStart = @"start";
+NSString *kHIDRemoteDNStatusActionStop = @"stop";
+NSString *kHIDRemoteDNStatusActionUpdate = @"update";
diff --git a/tools/EventClients/Clients/OSXRemote/RemoteControlWrapper/AppleRemote.h b/tools/EventClients/Clients/OSXRemote/RemoteControlWrapper/AppleRemote.h
deleted file mode 100644
index 4bb2f0998d..0000000000
--- a/tools/EventClients/Clients/OSXRemote/RemoteControlWrapper/AppleRemote.h
+++ /dev/null
@@ -1,44 +0,0 @@
-/*****************************************************************************
- * RemoteControlWrapper.h
- * RemoteControlWrapper
- *
- * Created by Martin Kahr on 11.03.06 under a MIT-style license.
- * Copyright (c) 2006 martinkahr.com. All rights reserved.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included
- * in all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- *
- *****************************************************************************/
-
-#import <Cocoa/Cocoa.h>
-#import "HIDRemoteControlDevice.h"
-
-/* Interacts with the Apple Remote Control HID device
- The class is not thread safe
- */
-@interface AppleRemote : HIDRemoteControlDevice {
- int deviceID;
-}
-
-//AppleRemote supports different device IDs (as long they are not paired)
-//the deviceID of last sent button can be queried with - (int) deviceID
-- (int) deviceID;
-
-//overwritten from baseclass to get notified of device changes
-- (eCookieModifier) handleCookie: (long)f_cookie value:(int) f_value;
-@end
diff --git a/tools/EventClients/Clients/OSXRemote/RemoteControlWrapper/AppleRemote.m b/tools/EventClients/Clients/OSXRemote/RemoteControlWrapper/AppleRemote.m
deleted file mode 100644
index 152e755aa5..0000000000
--- a/tools/EventClients/Clients/OSXRemote/RemoteControlWrapper/AppleRemote.m
+++ /dev/null
@@ -1,108 +0,0 @@
-/*****************************************************************************
- * RemoteControlWrapper.m
- * RemoteControlWrapper
- *
- * Created by Martin Kahr on 11.03.06 under a MIT-style license.
- * Copyright (c) 2006 martinkahr.com. All rights reserved.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included
- * in all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- *
- *****************************************************************************/
-
-#import "AppleRemote.h"
-
-#import <mach/mach.h>
-#import <mach/mach_error.h>
-#import <IOKit/IOKitLib.h>
-#import <IOKit/IOCFPlugIn.h>
-#import <IOKit/hid/IOHIDKeys.h>
-
-const char* AppleRemoteDeviceName = "AppleIRController";
-
-// the WWDC 07 Leopard Build is missing the constant
-#ifndef NSAppKitVersionNumber10_4
-#define NSAppKitVersionNumber10_4 824
-#endif
-
-@implementation AppleRemote
-
-+ (const char*) remoteControlDeviceName {
- return AppleRemoteDeviceName;
-}
-
-- (void) setCookieMappingInDictionary: (NSMutableDictionary*) _cookieToButtonMapping {
- if (floor(NSAppKitVersionNumber) <= NSAppKitVersionNumber10_4) {
- // 10.4.x Tiger
- [_cookieToButtonMapping setObject:[NSNumber numberWithInt:kRemoteButtonPlus] forKey:@"14_12_11_6_"];
- [_cookieToButtonMapping setObject:[NSNumber numberWithInt:kRemoteButtonMinus] forKey:@"14_13_11_6_"];
- [_cookieToButtonMapping setObject:[NSNumber numberWithInt:kRemoteButtonMenu] forKey:@"14_7_6_14_7_6_"];
- [_cookieToButtonMapping setObject:[NSNumber numberWithInt:kRemoteButtonPlay] forKey:@"14_8_6_14_8_6_"];
- [_cookieToButtonMapping setObject:[NSNumber numberWithInt:kRemoteButtonRight] forKey:@"14_9_6_14_9_6_"];
- [_cookieToButtonMapping setObject:[NSNumber numberWithInt:kRemoteButtonLeft] forKey:@"14_10_6_14_10_6_"];
- [_cookieToButtonMapping setObject:[NSNumber numberWithInt:kRemoteButtonRight_Hold] forKey:@"14_6_4_2_"];
- [_cookieToButtonMapping setObject:[NSNumber numberWithInt:kRemoteButtonLeft_Hold] forKey:@"14_6_3_2_"];
- [_cookieToButtonMapping setObject:[NSNumber numberWithInt:kRemoteButtonMenu_Hold] forKey:@"14_6_14_6_"];
- [_cookieToButtonMapping setObject:[NSNumber numberWithInt:kRemoteButtonPlay_Hold] forKey:@"18_14_6_18_14_6_"];
- [_cookieToButtonMapping setObject:[NSNumber numberWithInt:kRemoteControl_Switched] forKey:@"19_"];
- } else {
- // 10.5.x Leopard
- [_cookieToButtonMapping setObject:[NSNumber numberWithInt:kRemoteButtonPlus] forKey:@"31_29_28_19_18_"];
- [_cookieToButtonMapping setObject:[NSNumber numberWithInt:kRemoteButtonMinus] forKey:@"31_30_28_19_18_"];
- [_cookieToButtonMapping setObject:[NSNumber numberWithInt:kRemoteButtonMenu] forKey:@"31_20_19_18_31_20_19_18_"];
- [_cookieToButtonMapping setObject:[NSNumber numberWithInt:kRemoteButtonPlay] forKey:@"31_21_19_18_31_21_19_18_"];
- [_cookieToButtonMapping setObject:[NSNumber numberWithInt:kRemoteButtonRight] forKey:@"31_22_19_18_31_22_19_18_"];
- [_cookieToButtonMapping setObject:[NSNumber numberWithInt:kRemoteButtonLeft] forKey:@"31_23_19_18_31_23_19_18_"];
- [_cookieToButtonMapping setObject:[NSNumber numberWithInt:kRemoteButtonRight_Hold] forKey:@"31_19_18_4_2_"];
- [_cookieToButtonMapping setObject:[NSNumber numberWithInt:kRemoteButtonLeft_Hold] forKey:@"31_19_18_3_2_"];
- [_cookieToButtonMapping setObject:[NSNumber numberWithInt:kRemoteButtonMenu_Hold] forKey:@"31_19_18_31_19_18_"];
- [_cookieToButtonMapping setObject:[NSNumber numberWithInt:kRemoteButtonPlay_Hold] forKey:@"35_31_19_18_35_31_19_18_"];
- [_cookieToButtonMapping setObject:[NSNumber numberWithInt:kRemoteControl_Switched] forKey:@"19_"];
- [_cookieToButtonMapping setObject:[NSNumber numberWithInt:kRemoteControl_Switched] forKey:@"39_"];
- }
-}
-
-- (void) sendRemoteButtonEvent: (RemoteControlEventIdentifier) event pressedDown: (BOOL) pressedDown {
- if (pressedDown == NO && event == kRemoteButtonMenu_Hold) {
- // There is no seperate event for pressed down on menu hold. We are simulating that event here
- [super sendRemoteButtonEvent:event pressedDown:YES];
- }
-
- [super sendRemoteButtonEvent:event pressedDown:pressedDown];
-
- if (pressedDown && (event == kRemoteButtonRight || event == kRemoteButtonLeft || event == kRemoteButtonPlay || event == kRemoteButtonMenu || event == kRemoteButtonPlay_Hold)) {
- // There is no seperate event when the button is being released. We are simulating that event here
- [super sendRemoteButtonEvent:event pressedDown:NO];
- }
-}
-
-- (eCookieModifier) handleCookie: (long)f_cookie value:(int) f_value {
- switch(f_cookie)
- {
- case 39:
- deviceID = f_value;
- return PASS_COOKIE;
- default:
- return [super handleCookie:f_cookie value:f_value];
- }
-}
-
-- (int) deviceID {
- return deviceID;
-}
-@end
diff --git a/tools/EventClients/Clients/OSXRemote/RemoteControlWrapper/GlobalKeyboardDevice.h b/tools/EventClients/Clients/OSXRemote/RemoteControlWrapper/GlobalKeyboardDevice.h
deleted file mode 100644
index bcb11b4245..0000000000
--- a/tools/EventClients/Clients/OSXRemote/RemoteControlWrapper/GlobalKeyboardDevice.h
+++ /dev/null
@@ -1,49 +0,0 @@
-/*****************************************************************************
- * GlobalKeyboardDevice.h
- * RemoteControlWrapper
- *
- * Created by Martin Kahr on 11.03.06 under a MIT-style license.
- * Copyright (c) 2006 martinkahr.com. All rights reserved.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included
- * in all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- *
- *****************************************************************************/
-
-#import <Cocoa/Cocoa.h>
-#import <Carbon/Carbon.h>
-
-#import "RemoteControl.h"
-
-/*
- This class registers for a number of global keyboard shortcuts to simulate a remote control
- */
-@interface GlobalKeyboardDevice : RemoteControl {
-
- NSMutableDictionary* hotKeyRemoteEventMapping;
- EventHandlerRef eventHandlerRef;
-
-}
-
-- (void) mapRemoteButton: (RemoteControlEventIdentifier) remoteButtonIdentifier defaultKeycode: (unsigned int) defaultKeycode defaultModifiers: (unsigned int) defaultModifiers;
-
-- (BOOL)registerHotKeyCode: (unsigned int) keycode modifiers: (unsigned int) modifiers remoteEventIdentifier: (RemoteControlEventIdentifier) identifier;
-
-static OSStatus hotKeyEventHandler(EventHandlerCallRef inHandlerRef, EventRef inEvent, void* refCon );
-
-@end
diff --git a/tools/EventClients/Clients/OSXRemote/RemoteControlWrapper/GlobalKeyboardDevice.m b/tools/EventClients/Clients/OSXRemote/RemoteControlWrapper/GlobalKeyboardDevice.m
deleted file mode 100644
index f568d1f1a3..0000000000
--- a/tools/EventClients/Clients/OSXRemote/RemoteControlWrapper/GlobalKeyboardDevice.m
+++ /dev/null
@@ -1,241 +0,0 @@
-/*****************************************************************************
- * GlobalKeyboardDevice.m
- * RemoteControlWrapper
- *
- * Created by Martin Kahr on 11.03.06 under a MIT-style license.
- * Copyright (c) 2006 martinkahr.com. All rights reserved.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included
- * in all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- *
- *****************************************************************************/
-
-
-#import "GlobalKeyboardDevice.h"
-
-#define F1 122
-#define F2 120
-#define F3 99
-#define F4 118
-#define F5 96
-#define F6 97
-#define F7 98
-
-/*
- the following default keys are read and shall be used to change the keyboard mapping
-
- mac.remotecontrols.GlobalKeyboardDevice.plus_modifiers
- mac.remotecontrols.GlobalKeyboardDevice.plus_keycode
- mac.remotecontrols.GlobalKeyboardDevice.minus_modifiers
- mac.remotecontrols.GlobalKeyboardDevice.minus_keycode
- mac.remotecontrols.GlobalKeyboardDevice.play_modifiers
- mac.remotecontrols.GlobalKeyboardDevice.play_keycode
- mac.remotecontrols.GlobalKeyboardDevice.left_modifiers
- mac.remotecontrols.GlobalKeyboardDevice.left_keycode
- mac.remotecontrols.GlobalKeyboardDevice.right_modifiers
- mac.remotecontrols.GlobalKeyboardDevice.right_keycode
- mac.remotecontrols.GlobalKeyboardDevice.menu_modifiers
- mac.remotecontrols.GlobalKeyboardDevice.menu_keycode
- mac.remotecontrols.GlobalKeyboardDevice.playhold_modifiers
- mac.remotecontrols.GlobalKeyboardDevice.playhold_keycode
- */
-
-
-@implementation GlobalKeyboardDevice
-
-- (id) initWithDelegate: (id) _remoteControlDelegate {
- if (self = [super initWithDelegate: _remoteControlDelegate]) {
- hotKeyRemoteEventMapping = [[NSMutableDictionary alloc] init];
-
- unsigned int modifiers = cmdKey + shiftKey /*+ optionKey*/ + controlKey;
-
- [self mapRemoteButton:kRemoteButtonPlus defaultKeycode:F1 defaultModifiers:modifiers];
- [self mapRemoteButton:kRemoteButtonMinus defaultKeycode:F2 defaultModifiers:modifiers];
- [self mapRemoteButton:kRemoteButtonPlay defaultKeycode:F3 defaultModifiers:modifiers];
- [self mapRemoteButton:kRemoteButtonLeft defaultKeycode:F4 defaultModifiers:modifiers];
- [self mapRemoteButton:kRemoteButtonRight defaultKeycode:F5 defaultModifiers:modifiers];
- [self mapRemoteButton:kRemoteButtonMenu defaultKeycode:F6 defaultModifiers:modifiers];
- [self mapRemoteButton:kRemoteButtonPlay_Hold defaultKeycode:F7 defaultModifiers:modifiers];
- }
- return self;
-}
-
-- (void) dealloc {
- [hotKeyRemoteEventMapping release];
- [super dealloc];
-}
-
-- (void) mapRemoteButton: (RemoteControlEventIdentifier) remoteButtonIdentifier defaultKeycode: (unsigned int) defaultKeycode defaultModifiers: (unsigned int) defaultModifiers {
- NSString* defaultsKey;
-
- switch(remoteButtonIdentifier) {
- case kRemoteButtonPlus:
- defaultsKey = @"plus";
- break;
- case kRemoteButtonMinus:
- defaultsKey = @"minus";
- break;
- case kRemoteButtonMenu:
- defaultsKey = @"menu";
- break;
- case kRemoteButtonPlay:
- defaultsKey = @"play";
- break;
- case kRemoteButtonRight:
- defaultsKey = @"right";
- break;
- case kRemoteButtonLeft:
- defaultsKey = @"left";
- break;
- case kRemoteButtonPlay_Hold:
- defaultsKey = @"playhold";
- break;
- default:
- NSLog(@"Unknown global keyboard defaults key for remote button identifier %d", remoteButtonIdentifier);
- }
-
- NSNumber* modifiersCfg = [[NSUserDefaults standardUserDefaults] objectForKey: [NSString stringWithFormat: @"mac.remotecontrols.GlobalKeyboardDevice.%@_modifiers", defaultsKey]];
- NSNumber* keycodeCfg = [[NSUserDefaults standardUserDefaults] objectForKey: [NSString stringWithFormat: @"mac.remotecontrols.GlobalKeyboardDevice.%@_keycode", defaultsKey]];
-
- unsigned int modifiers = defaultModifiers;
- if (modifiersCfg) modifiers = [modifiersCfg unsignedIntValue];
-
- unsigned int keycode = defaultKeycode;
- if (keycodeCfg) keycode = [keycodeCfg unsignedIntValue];
-
- [self registerHotKeyCode: keycode modifiers: modifiers remoteEventIdentifier: remoteButtonIdentifier];
-}
-
-- (void) setListeningToRemote: (BOOL) value {
- if (value == [self isListeningToRemote]) return;
- if (value) {
- [self startListening: self];
- } else {
- [self stopListening: self];
- }
-}
-- (BOOL) isListeningToRemote {
- return (eventHandlerRef!=NULL);
-}
-
-- (IBAction) startListening: (id) sender {
-
- if (eventHandlerRef) return;
-
- EventTypeSpec eventSpec[2] = {
- { kEventClassKeyboard, kEventHotKeyPressed },
- { kEventClassKeyboard, kEventHotKeyReleased }
- };
-
- InstallEventHandler( GetEventDispatcherTarget(),
- (EventHandlerProcPtr)hotKeyEventHandler,
- 2, eventSpec, self, &eventHandlerRef);
-}
-- (IBAction) stopListening: (id) sender {
- RemoveEventHandler(eventHandlerRef);
- eventHandlerRef = NULL;
-}
-
-- (BOOL) sendsEventForButtonIdentifier: (RemoteControlEventIdentifier) identifier {
- NSEnumerator* values = [hotKeyRemoteEventMapping objectEnumerator];
- NSNumber* remoteIdentifier;
- while( (remoteIdentifier = [values nextObject]) ) {
- if ([remoteIdentifier unsignedIntValue] == identifier) return YES;
- }
- return NO;
-}
-
-+ (const char*) remoteControlDeviceName {
- return "Keyboard";
-}
-
-- (BOOL)registerHotKeyCode: (unsigned int) keycode modifiers: (unsigned int) modifiers remoteEventIdentifier: (RemoteControlEventIdentifier) identifier {
- OSStatus err;
- EventHotKeyID hotKeyID;
- EventHotKeyRef carbonHotKey;
-
- hotKeyID.signature = 'PTHk';
- hotKeyID.id = (long)keycode;
-
- err = RegisterEventHotKey(keycode, modifiers, hotKeyID, GetEventDispatcherTarget(), (int)nil, &carbonHotKey );
-
- if( err )
- return NO;
-
- [hotKeyRemoteEventMapping setObject: [NSNumber numberWithInt:identifier] forKey: [NSNumber numberWithUnsignedInt: hotKeyID.id]];
-
- return YES;
-}
-/*
- - (void)unregisterHotKey: (PTHotKey*)hotKey
- {
- OSStatus err;
- EventHotKeyRef carbonHotKey;
- NSValue* key;
-
- if( [[self allHotKeys] containsObject: hotKey] == NO )
- return;
-
- carbonHotKey = [self _carbonHotKeyForHotKey: hotKey];
- NSAssert( carbonHotKey != nil, @"" );
-
- err = UnregisterEventHotKey( carbonHotKey );
- //Watch as we ignore 'err':
-
- key = [NSValue valueWithPointer: carbonHotKey];
- [mHotKeys removeObjectForKey: key];
-
- [self _updateEventHandler];
-
- //See that? Completely ignored
- }
- */
-
-- (RemoteControlEventIdentifier) remoteControlEventIdentifierForID: (unsigned int) id {
- NSNumber* remoteEventIdentifier = [hotKeyRemoteEventMapping objectForKey:[NSNumber numberWithUnsignedInt: id]];
- return [remoteEventIdentifier unsignedIntValue];
-}
-
-- (void) sendRemoteButtonEvent: (RemoteControlEventIdentifier) event pressedDown: (BOOL) pressedDown {
- [delegate sendRemoteButtonEvent: event pressedDown: pressedDown remoteControl:self];
-}
-
-static RemoteControlEventIdentifier lastEvent;
-
-static OSStatus hotKeyEventHandler(EventHandlerCallRef inHandlerRef, EventRef inEvent, void* userData )
-{
- GlobalKeyboardDevice* keyboardDevice = (GlobalKeyboardDevice*) userData;
- EventHotKeyID hkCom;
- GetEventParameter(inEvent,kEventParamDirectObject,typeEventHotKeyID,NULL,sizeof(hkCom),NULL,&hkCom);
-
- RemoteControlEventIdentifier identifier = [keyboardDevice remoteControlEventIdentifierForID:hkCom.id];
- if (identifier == 0) return noErr;
-
- BOOL pressedDown = YES;
- if (identifier != lastEvent) {
- lastEvent = identifier;
- } else {
- lastEvent = 0;
- pressedDown = NO;
- }
- [keyboardDevice sendRemoteButtonEvent: identifier pressedDown: pressedDown];
-
- return noErr;
-}
-
-@end
diff --git a/tools/EventClients/Clients/OSXRemote/RemoteControlWrapper/HIDRemoteControlDevice.h b/tools/EventClients/Clients/OSXRemote/RemoteControlWrapper/HIDRemoteControlDevice.h
deleted file mode 100644
index 1bd3dff60a..0000000000
--- a/tools/EventClients/Clients/OSXRemote/RemoteControlWrapper/HIDRemoteControlDevice.h
+++ /dev/null
@@ -1,77 +0,0 @@
-/*****************************************************************************
- * HIDRemoteControlDevice.h
- * RemoteControlWrapper
- *
- * Created by Martin Kahr on 11.03.06 under a MIT-style license.
- * Copyright (c) 2006 martinkahr.com. All rights reserved.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included
- * in all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- *
- *****************************************************************************/
-
-#import <Cocoa/Cocoa.h>
-#import <Carbon/Carbon.h>
-#import <IOKit/hid/IOHIDLib.h>
-
-#import "RemoteControl.h"
-
-typedef enum _eCookieModifier{
- DISCARD_COOKIE = 0,
- PASS_COOKIE
-} eCookieModifier;
-
-/*
- Base class for HID based remote control devices
- */
-@interface HIDRemoteControlDevice : RemoteControl {
- IOHIDDeviceInterface** hidDeviceInterface;
- IOHIDQueueInterface** queue;
- NSMutableArray* allCookies;
- NSMutableDictionary* cookieToButtonMapping;
- CFRunLoopSourceRef eventSource;
-
- BOOL fixSecureEventInputBug;
- BOOL openInExclusiveMode;
- BOOL processesBacklog;
-
- int supportedButtonEvents;
-
- EventHandlerUPP appSwitchedHandlerUPP;
- EventHandlerRef appSwitchedHandlerRef;
-}
-
-// 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;
-
-// methods that should be overwritten by subclasses
-- (void) setCookieMappingInDictionary: (NSMutableDictionary*) cookieToButtonMapping;
-
-- (void) sendRemoteButtonEvent: (RemoteControlEventIdentifier) event pressedDown: (BOOL) pressedDown;
-
-//overwrite this to be able to interact with cookie handling
-//by default (f_cookie == 5) is discarded
-- (eCookieModifier) handleCookie: (long)f_cookie value:(int) f_value;
-
-+ (BOOL) isRemoteAvailable;
-
-@end
diff --git a/tools/EventClients/Clients/OSXRemote/RemoteControlWrapper/HIDRemoteControlDevice.m b/tools/EventClients/Clients/OSXRemote/RemoteControlWrapper/HIDRemoteControlDevice.m
deleted file mode 100644
index 5fa61c46b5..0000000000
--- a/tools/EventClients/Clients/OSXRemote/RemoteControlWrapper/HIDRemoteControlDevice.m
+++ /dev/null
@@ -1,547 +0,0 @@
-/*****************************************************************************
- * HIDRemoteControlDevice.m
- * RemoteControlWrapper
- *
- * Created by Martin Kahr on 11.03.06 under a MIT-style license.
- * Copyright (c) 2006 martinkahr.com. All rights reserved.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included
- * in all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- *
- *****************************************************************************/
-
-#import "HIDRemoteControlDevice.h"
-
-#import <mach/mach.h>
-#import <mach/mach_error.h>
-#import <IOKit/IOKitLib.h>
-#import <IOKit/IOCFPlugIn.h>
-#import <IOKit/hid/IOHIDKeys.h>
-#import "XBMCDebugHelpers.h"
-
-@interface HIDRemoteControlDevice (PrivateMethods)
-- (NSDictionary*) cookieToButtonMapping;
-- (IOHIDQueueInterface**) queue;
-- (IOHIDDeviceInterface**) hidDeviceInterface;
-- (void) removeNotifcationObserver;
-- (void) remoteControlAvailable:(NSNotification *)notification;
-- (void) enableSecureInputFix;
-- (void) disableSecureInputFix;
-@end
-
-@interface HIDRemoteControlDevice (IOKitMethods)
-+ (io_object_t) findRemoteDevice;
-- (IOHIDDeviceInterface**) createInterfaceForDevice: (io_object_t) hidDevice;
-- (BOOL) initializeCookies;
-- (BOOL) openDevice;
-@end
-
-//handler to regrab device if openend in exclusive mode on app-switches
-//installed in startListening and removed in stopListening
-pascal OSStatus appSwitchedEventHandler(EventHandlerCallRef nextHandler,
- EventRef switchEvent,
- void* userData);
-
-@implementation HIDRemoteControlDevice
-
-+ (const char*) remoteControlDeviceName {
- return "";
-}
-
-+ (BOOL) isRemoteAvailable {
- io_object_t hidDevice = [self findRemoteDevice];
- if (hidDevice != 0) {
- IOObjectRelease(hidDevice);
- return YES;
- } else {
- return NO;
- }
-}
-
-- (id) initWithDelegate: (id) _remoteControlDelegate {
- if ([[self class] isRemoteAvailable] == NO) return nil;
-
- if ( self = [super initWithDelegate: _remoteControlDelegate] ) {
- openInExclusiveMode = YES;
- queue = NULL;
- hidDeviceInterface = NULL;
- cookieToButtonMapping = [[NSMutableDictionary alloc] init];
-
- [self setCookieMappingInDictionary: cookieToButtonMapping];
-
- NSEnumerator* enumerator = [cookieToButtonMapping objectEnumerator];
- NSNumber* identifier;
- supportedButtonEvents = 0;
- while(identifier = [enumerator nextObject]) {
- supportedButtonEvents |= [identifier intValue];
- }
-
- fixSecureEventInputBug = [[NSUserDefaults standardUserDefaults] boolForKey: @"remoteControlWrapperFixSecureEventInputBug"];
- appSwitchedHandlerUPP = NewEventHandlerUPP(appSwitchedEventHandler);
- }
-
- return self;
-}
-
-- (void) dealloc {
- [self removeNotifcationObserver];
- [self stopListening:self];
- [cookieToButtonMapping release];
- [super dealloc];
-}
-
-- (void) sendRemoteButtonEvent: (RemoteControlEventIdentifier) event pressedDown: (BOOL) pressedDown {
- [delegate sendRemoteButtonEvent: event pressedDown: pressedDown remoteControl:self];
-}
-
-- (void) setCookieMappingInDictionary: (NSMutableDictionary*) cookieToButtonMapping {
-}
-- (int) remoteIdSwitchCookie {
- return 0;
-}
-
-- (BOOL) sendsEventForButtonIdentifier: (RemoteControlEventIdentifier) identifier {
- return (supportedButtonEvents & identifier) == identifier;
-}
-
-- (BOOL) isListeningToRemote {
- return (hidDeviceInterface != NULL && allCookies != NULL && queue != NULL);
-}
-
-- (void) setListeningToRemote: (BOOL) value {
- if (value == NO) {
- [self stopListening:self];
- } else {
- [self startListening:self];
- }
-}
-
-- (BOOL) isOpenInExclusiveMode {
- return openInExclusiveMode;
-}
-- (void) setOpenInExclusiveMode: (BOOL) value {
- openInExclusiveMode = value;
-}
-
-- (BOOL) processesBacklog {
- return processesBacklog;
-}
-- (void) setProcessesBacklog: (BOOL) value {
- processesBacklog = value;
-}
-
-//handler to regrab device if openend in exclusive mode on app-switches
-//installed in startListening and removed in stopListening
-pascal OSStatus appSwitchedEventHandler(EventHandlerCallRef nextHandler,
- EventRef switchEvent,
- void* userData)
-{
- HIDRemoteControlDevice* p_this = (HIDRemoteControlDevice*)userData;
- if (p_this->hidDeviceInterface)
- {
- if ((*(p_this->hidDeviceInterface))->close(p_this->hidDeviceInterface) != KERN_SUCCESS)
- ELOG("failed closing Apple Remote device\n");
-
- if ((*(p_this->hidDeviceInterface))->open(p_this->hidDeviceInterface, kIOHIDOptionsTypeSeizeDevice) != KERN_SUCCESS)
- ELOG("failed opening Apple Remote device\n");
- }
- //DLOG("Reopened Apple Remote in exclusive mode\n");
- return 0;
-}
-
-- (IBAction) startListening: (id) sender {
- if ([self isListeningToRemote]) return;
-
- // 4th July 2007
- //
- // A security update in february of 2007 introduced an odd behavior.
- // Whenever SecureEventInput is activated or deactivated the exclusive access
- // to the remote control device is lost. This leads to very strange behavior where
- // a press on the Menu button activates FrontRow while your app still gets the event.
- // A great number of people have complained about this.
- //
- // Enabling the SecureEventInput and keeping it enabled does the trick.
- //
- // I'm pretty sure this is a kind of bug at Apple and I'm in contact with the responsible
- // Apple Engineer. This solution is not a perfect one - I know.
- // One of the side effects is that applications that listen for special global keyboard shortcuts (like Quicksilver)
- // may get into problems as they no longer get the events.
- // As there is no official Apple Remote API from Apple I also failed to open a technical incident on this.
- //
- // Note that there is a corresponding DisableSecureEventInput in the stopListening method below.
- //
- [self enableSecureInputFix];
-
- [self removeNotifcationObserver];
-
- io_object_t hidDevice = [[self class] findRemoteDevice];
- if (hidDevice == 0) return;
-
- if ([self createInterfaceForDevice:hidDevice] == NULL) {
- goto error;
- }
-
- if ([self initializeCookies]==NO) {
- goto error;
- }
-
- if ([self openDevice]==NO) {
- goto error;
- }
- // be KVO friendly
- [self willChangeValueForKey:@"listeningToRemote"];
- [self didChangeValueForKey:@"listeningToRemote"];
- goto cleanup;
-
-error:
- [self stopListening:self];
- [self disableSecureInputFix];
-
-cleanup:
- IOObjectRelease(hidDevice);
-}
-
-- (IBAction) stopListening: (id) sender {
- if ([self isListeningToRemote]==NO) return;
-
- BOOL sendNotification = NO;
-
- if (eventSource != NULL) {
- CFRunLoopRemoveSource(CFRunLoopGetCurrent(), eventSource, kCFRunLoopDefaultMode);
- CFRelease(eventSource);
- eventSource = NULL;
- }
- if (queue != NULL) {
- (*queue)->stop(queue);
-
- //dispose of queue
- (*queue)->dispose(queue);
-
- //release the queue we allocated
- (*queue)->Release(queue);
-
- queue = NULL;
-
- sendNotification = YES;
- }
-
- if (allCookies != nil) {
- [allCookies autorelease];
- allCookies = nil;
- }
-
- if (hidDeviceInterface != NULL) {
- //close the device
- (*hidDeviceInterface)->close(hidDeviceInterface);
-
- //release the interface
- (*hidDeviceInterface)->Release(hidDeviceInterface);
-
- hidDeviceInterface = NULL;
- }
- [self disableSecureInputFix];
-
- if ([self isOpenInExclusiveMode] && sendNotification) {
- [[self class] sendFinishedNotifcationForAppIdentifier: nil];
- }
- // be KVO friendly
- [self willChangeValueForKey:@"listeningToRemote"];
- [self didChangeValueForKey:@"listeningToRemote"];
-}
-
-- (eCookieModifier) handleCookie: (long)f_cookie value:(int) f_value {
- if(f_cookie == 5)
- return DISCARD_COOKIE;
- else
- return PASS_COOKIE;
-}
-
-@end
-
-@implementation HIDRemoteControlDevice (PrivateMethods)
-
-- (IOHIDQueueInterface**) queue {
- return queue;
-}
-
-- (IOHIDDeviceInterface**) hidDeviceInterface {
- return hidDeviceInterface;
-}
-
-
-- (NSDictionary*) cookieToButtonMapping {
- return cookieToButtonMapping;
-}
-
-- (void) removeNotifcationObserver {
- [[NSDistributedNotificationCenter defaultCenter] removeObserver:self name:FINISHED_USING_REMOTE_CONTROL_NOTIFICATION object:nil];
-}
-
-- (void) remoteControlAvailable:(NSNotification *)notification {
- [self removeNotifcationObserver];
- [self startListening: self];
-}
-
-- (void) enableSecureInputFix {
- if ([self isOpenInExclusiveMode]) {
- //2 ways to fix exclusive mode, either the one mentioned above
- if (fixSecureEventInputBug)
- EnableSecureEventInput();
- else {
- //or registering for all app-switch events and just reopening the device on each switch
- const EventTypeSpec applicationEvents[] = { { kEventClassApplication, kEventAppFrontSwitched } };
- InstallApplicationEventHandler(appSwitchedHandlerUPP,
- GetEventTypeCount(applicationEvents), applicationEvents, self, &appSwitchedHandlerRef);
- }
- }
-}
-
-- (void) disableSecureInputFix{
- if ([self isOpenInExclusiveMode]){
- if(fixSecureEventInputBug)
- DisableSecureEventInput();
- else{
- RemoveEventHandler(appSwitchedHandlerRef);
- }
- }
-}
-
-@end
-
-/* Callback method for the device queue
- 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) {
- if (target < 0) {
- NSLog(@"QueueCallbackFunction called with invalid target!");
- return;
- }
- NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
-
- HIDRemoteControlDevice* remote = (HIDRemoteControlDevice*)target;
- IOHIDEventStruct event;
- AbsoluteTime zeroTime = {0,0};
- NSMutableString* cookieString = [NSMutableString stringWithCapacity: 10];
- SInt32 sumOfValues = 0;
- NSNumber* lastSubButtonId = nil;
- while (result == kIOReturnSuccess)
- {
- 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 handleCookie:(long)event.elementCookie value:event.value] != DISCARD_COOKIE){
- sumOfValues+=event.value;
- [cookieString appendString:[NSString stringWithFormat:@"%d_", event.elementCookie]];
- }
- //check if this is a valid button
- NSNumber* buttonId = [[remote cookieToButtonMapping] objectForKey: cookieString];
- if (buttonId != nil){
- if([remote processesBacklog]) {
- //send the button
- [remote sendRemoteButtonEvent: [buttonId intValue] pressedDown: (sumOfValues>0)];
- //reset
- } else {
- //store button for later use
- lastSubButtonId = buttonId;
- }
- sumOfValues = 0;
- cookieString = [NSMutableString stringWithCapacity: 10];
- }
- }
- if ([remote processesBacklog] == NO && lastSubButtonId != 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");
- [remote sendRemoteButtonEvent: [lastSubButtonId intValue] pressedDown: (sumOfValues>0)];
- }
- if ([cookieString length] > 0) {
- NSLog(@"Unknown button for cookiestring %@", cookieString);
- }
- [pool release];
-}
-
-@implementation HIDRemoteControlDevice (IOKitMethods)
-
-- (IOHIDDeviceInterface**) createInterfaceForDevice: (io_object_t) hidDevice {
- io_name_t className;
- IOCFPlugInInterface** plugInInterface = NULL;
- HRESULT plugInResult = S_OK;
- SInt32 score = 0;
- IOReturn ioReturnValue = kIOReturnSuccess;
-
- hidDeviceInterface = NULL;
-
- ioReturnValue = IOObjectGetClass(hidDevice, className);
-
- if (ioReturnValue != kIOReturnSuccess) {
- NSLog(@"Error: Failed to get class name.");
- return NULL;
- }
-
- ioReturnValue = IOCreatePlugInInterfaceForService(hidDevice,
- kIOHIDDeviceUserClientTypeID,
- kIOCFPlugInInterfaceID,
- &plugInInterface,
- &score);
- if (ioReturnValue == kIOReturnSuccess)
- {
- //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) {
- NSLog(@"Error: Couldn't create HID class device interface");
- }
- // Release
- if (plugInInterface) (*plugInInterface)->Release(plugInInterface);
- }
- return hidDeviceInterface;
-}
-
-- (BOOL) initializeCookies {
- IOHIDDeviceInterface122** handle = (IOHIDDeviceInterface122**)hidDeviceInterface;
- IOHIDElementCookie cookie;
- long usage;
- long usagePage;
- id object;
- 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);
- */
- allCookies = [[NSMutableArray alloc] init];
-
- NSEnumerator *elementsEnumerator = [elements objectEnumerator];
-
- while (element = [elementsEnumerator nextObject]) {
- //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.
-
- IOHIDElementCookie cookie;
- NSEnumerator *allCookiesEnumerator = [allCookies objectEnumerator];
-
- while (cookie = (IOHIDElementCookie)[[allCookiesEnumerator nextObject] intValue]) {
- (*queue)->addElement(queue, cookie, 0);
- }
-
- // add callback for async events
- ioReturnValue = (*queue)->createAsyncEventSource(queue, &eventSource);
- if (ioReturnValue == KERN_SUCCESS) {
- ioReturnValue = (*queue)->setEventCallout(queue,QueueCallbackFunction, self, NULL);
- if (ioReturnValue == KERN_SUCCESS) {
- CFRunLoopAddSource(CFRunLoopGetCurrent(), eventSource, kCFRunLoopDefaultMode);
-
- //start data delivery to queue
- (*queue)->start(queue);
- return YES;
- } else {
- NSLog(@"Error when setting event callback");
- }
- } else {
- NSLog(@"Error when creating async event source");
- }
- } else {
- NSLog(@"Error when opening device");
- }
- } else if (ioReturnValue == kIOReturnExclusiveAccess) {
- // the device is used exclusive by another application
-
- // 1. we register for the FINISHED_USING_REMOTE_CONTROL_NOTIFICATION notification
- [[NSDistributedNotificationCenter defaultCenter] addObserver:self selector:@selector(remoteControlAvailable:) name:FINISHED_USING_REMOTE_CONTROL_NOTIFICATION object:nil];
-
- // 2. send a distributed notification that we wanted to use the remote control
- [[self class] sendRequestForRemoteControlNotification];
- }
- return NO;
-}
-
-+ (io_object_t) findRemoteDevice {
- CFMutableDictionaryRef hidMatchDictionary = NULL;
- 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([self remoteControlDeviceName]);
-
- // 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;
-}
-
-@end
-
diff --git a/tools/EventClients/Clients/OSXRemote/RemoteControlWrapper/IRKeyboardEmu.h b/tools/EventClients/Clients/OSXRemote/RemoteControlWrapper/IRKeyboardEmu.h
deleted file mode 100644
index 8a842da8f3..0000000000
--- a/tools/EventClients/Clients/OSXRemote/RemoteControlWrapper/IRKeyboardEmu.h
+++ /dev/null
@@ -1,16 +0,0 @@
-//
-// IRKeyboardEmu.h
-// XBMCHelper
-//
-// Created by Stephan Diederich on 14.04.09.
-// Copyright 2009 __MyCompanyName__. All rights reserved.
-//
-
-#import <Cocoa/Cocoa.h>
-#import "AppleRemote.h"
-
-@interface IRKeyboardEmu : AppleRemote {
-
-}
-
-@end
diff --git a/tools/EventClients/Clients/OSXRemote/RemoteControlWrapper/IRKeyboardEmu.m b/tools/EventClients/Clients/OSXRemote/RemoteControlWrapper/IRKeyboardEmu.m
deleted file mode 100644
index 5350e16c0c..0000000000
--- a/tools/EventClients/Clients/OSXRemote/RemoteControlWrapper/IRKeyboardEmu.m
+++ /dev/null
@@ -1,26 +0,0 @@
-//
-// IRKeyboardEmu.m
-// XBMCHelper
-//
-// Created by Stephan Diederich on 14.04.09.
-// Copyright 2009 __MyCompanyName__. All rights reserved.
-//
-
-#import "IRKeyboardEmu.h"
-
-
-@implementation IRKeyboardEmu
-
-+ (const char*) remoteControlDeviceName {
- return "IRKeyboardEmu";
-}
-
-- (void) sendRemoteButtonEvent: (RemoteControlEventIdentifier) event pressedDown: (BOOL) pressedDown {
- if (pressedDown == NO && event == kRemoteButtonMenu_Hold) {
- // There is no seperate event for pressed down on menu hold. We are simulating that event here
- [super sendRemoteButtonEvent:event pressedDown:YES];
- }
-
- [super sendRemoteButtonEvent:event pressedDown:pressedDown];
-}
-@end
diff --git a/tools/EventClients/Clients/OSXRemote/RemoteControlWrapper/KeyspanFrontRowControl.h b/tools/EventClients/Clients/OSXRemote/RemoteControlWrapper/KeyspanFrontRowControl.h
deleted file mode 100644
index 3a8224154f..0000000000
--- a/tools/EventClients/Clients/OSXRemote/RemoteControlWrapper/KeyspanFrontRowControl.h
+++ /dev/null
@@ -1,39 +0,0 @@
-/*****************************************************************************
- * KeyspanFrontRowControl.h
- * RemoteControlWrapper
- *
- * Created by Martin Kahr on 11.03.06 under a MIT-style license.
- * Copyright (c) 2006 martinkahr.com. All rights reserved.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included
- * in all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- *
- *****************************************************************************/
-
-
-#import <Cocoa/Cocoa.h>
-#import "HIDRemoteControlDevice.h"
-
-/* Interacts with the Keyspan FrontRow Remote Control HID device
- The class is not thread safe
- */
-@interface KeyspanFrontRowControl : HIDRemoteControlDevice {
-
-}
-
-@end
diff --git a/tools/EventClients/Clients/OSXRemote/RemoteControlWrapper/KeyspanFrontRowControl.m b/tools/EventClients/Clients/OSXRemote/RemoteControlWrapper/KeyspanFrontRowControl.m
deleted file mode 100644
index 7dbcc853ec..0000000000
--- a/tools/EventClients/Clients/OSXRemote/RemoteControlWrapper/KeyspanFrontRowControl.m
+++ /dev/null
@@ -1,87 +0,0 @@
-/*****************************************************************************
- * KeyspanFrontRowControl.m
- * RemoteControlWrapper
- *
- * Created by Martin Kahr on 11.03.06 under a MIT-style license.
- * Copyright (c) 2006 martinkahr.com. All rights reserved.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included
- * in all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- *
- *****************************************************************************/
-
-#import "KeyspanFrontRowControl.h"
-#import <mach/mach.h>
-#import <mach/mach_error.h>
-#import <IOKit/IOKitLib.h>
-#import <IOKit/IOCFPlugIn.h>
-#import <IOKit/hid/IOHIDKeys.h>
-
-@implementation KeyspanFrontRowControl
-
-- (void) setCookieMappingInDictionary: (NSMutableDictionary*) _cookieToButtonMapping {
- [_cookieToButtonMapping setObject:[NSNumber numberWithInt:kRemoteButtonPlus] forKey:@"11_18_99_10_"];
- [_cookieToButtonMapping setObject:[NSNumber numberWithInt:kRemoteButtonMinus] forKey:@"11_18_98_10_"];
- [_cookieToButtonMapping setObject:[NSNumber numberWithInt:kRemoteButtonMenu] forKey:@"11_18_58_10_"];
- [_cookieToButtonMapping setObject:[NSNumber numberWithInt:kRemoteButtonPlay] forKey:@"11_18_61_10_"];
- [_cookieToButtonMapping setObject:[NSNumber numberWithInt:kRemoteButtonRight] forKey:@"11_18_96_10_"];
- [_cookieToButtonMapping setObject:[NSNumber numberWithInt:kRemoteButtonLeft] forKey:@"11_18_97_10_"];
- /* hold events are not being send by this device
- [_cookieToButtonMapping setObject:[NSNumber numberWithInt:kRemoteButtonRight_Hold] forKey:@"14_6_4_2_"];
- [_cookieToButtonMapping setObject:[NSNumber numberWithInt:kRemoteButtonLeft_Hold] forKey:@"14_6_3_2_"];
- [_cookieToButtonMapping setObject:[NSNumber numberWithInt:kRemoteButtonMenu_Hold] forKey:@"14_6_14_6_"];
- [_cookieToButtonMapping setObject:[NSNumber numberWithInt:kRemoteButtonPlay_Sleep] forKey:@"18_14_6_18_14_6_"];
- [_cookieToButtonMapping setObject:[NSNumber numberWithInt:kRemoteControl_Switched] forKey:@"19_"];
- */
-}
-
-+ (io_object_t) findRemoteDevice {
- CFMutableDictionaryRef hidMatchDictionary = NULL;
- IOReturn ioReturnValue = kIOReturnSuccess;
- io_iterator_t hidObjectIterator = 0;
- io_object_t hidDevice = 0;
- SInt32 idVendor = 1741;
- SInt32 idProduct = 0x420;
-
- // Set up a matching dictionary to search the I/O Registry by class
- // name for all HID class devices
- hidMatchDictionary = IOServiceMatching(kIOHIDDeviceKey);
-
- CFNumberRef numberRef = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &idVendor);
- CFDictionaryAddValue(hidMatchDictionary, CFSTR(kIOHIDVendorIDKey), numberRef);
- CFRelease(numberRef);
-
- numberRef = CFNumberCreate(kCFAllocatorDefault, kCFNumberSInt32Type, &idProduct);
- CFDictionaryAddValue(hidMatchDictionary, CFSTR(kIOHIDProductIDKey), numberRef);
- CFRelease(numberRef);
-
- // 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;
-
-}
-
-@end
diff --git a/tools/EventClients/Clients/OSXRemote/RemoteControlWrapper/MultiClickRemoteBehavior.h b/tools/EventClients/Clients/OSXRemote/RemoteControlWrapper/MultiClickRemoteBehavior.h
deleted file mode 100644
index 8b288604f7..0000000000
--- a/tools/EventClients/Clients/OSXRemote/RemoteControlWrapper/MultiClickRemoteBehavior.h
+++ /dev/null
@@ -1,90 +0,0 @@
-/*****************************************************************************
- * MultiClickRemoteBehavior.h
- * RemoteControlWrapper
- *
- * Created by Martin Kahr on 11.03.06 under a MIT-style license.
- * Copyright (c) 2006 martinkahr.com. All rights reserved.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included
- * in all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- *
- *****************************************************************************/
-
-
-#import <Cocoa/Cocoa.h>
-#import "RemoteControl.h"
-
-/**
- A behavior that adds multiclick and hold events on top of a device.
- Events are generated and send to a delegate
- */
-@interface MultiClickRemoteBehavior : NSObject {
- id delegate;
-
- // state for simulating plus/minus hold
- BOOL simulateHoldEvents;
- BOOL lastEventSimulatedHold;
- RemoteControlEventIdentifier lastHoldEvent;
- NSTimeInterval lastHoldEventTime;
-
- // state for multi click
- unsigned int clickCountEnabledButtons;
- NSTimeInterval maxClickTimeDifference;
- NSTimeInterval lastClickCountEventTime;
- RemoteControlEventIdentifier lastClickCountEvent;
- unsigned int eventClickCount;
-}
-
-- (id) init;
-
-// Delegates are not retained
-- (void) setDelegate: (id) delegate;
-- (id) delegate;
-
-// Simulating hold events does deactivate sending of individual requests for pressed down/released.
-// Instead special hold events are being triggered when the user is pressing and holding a button for a small period.
-// Simulation is activated only for those buttons and remote control that do not have a seperate event already
-- (BOOL) simulateHoldEvent;
-- (void) setSimulateHoldEvent: (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;
-
-@end
-
-/*
- * Method definitions for the delegate of the MultiClickRemoteBehavior class
- */
-@interface NSObject(MultiClickRemoteBehaviorDelegate)
-
-- (void) remoteButton: (RemoteControlEventIdentifier)buttonIdentifier pressedDown: (BOOL) pressedDown clickCount: (unsigned int) count;
-
-@end
diff --git a/tools/EventClients/Clients/OSXRemote/RemoteControlWrapper/MultiClickRemoteBehavior.m b/tools/EventClients/Clients/OSXRemote/RemoteControlWrapper/MultiClickRemoteBehavior.m
deleted file mode 100644
index 4b40fb3df8..0000000000
--- a/tools/EventClients/Clients/OSXRemote/RemoteControlWrapper/MultiClickRemoteBehavior.m
+++ /dev/null
@@ -1,210 +0,0 @@
-/*****************************************************************************
- * MultiClickRemoteBehavior.m
- * RemoteControlWrapper
- *
- * Created by Martin Kahr on 11.03.06 under a MIT-style license.
- * Copyright (c) 2006 martinkahr.com. All rights reserved.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included
- * in all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- *
- *****************************************************************************/
-
-#import "MultiClickRemoteBehavior.h"
-
-const NSTimeInterval DEFAULT_MAXIMUM_CLICK_TIME_DIFFERENCE=0.35;
-const NSTimeInterval HOLD_RECOGNITION_TIME_INTERVAL=0.4;
-
-@implementation MultiClickRemoteBehavior
-
-- (id) init {
- if (self = [super init]) {
- maxClickTimeDifference = DEFAULT_MAXIMUM_CLICK_TIME_DIFFERENCE;
- }
- return self;
-}
-
-// 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 {
- if (_delegate && [_delegate respondsToSelector:@selector(remoteButton:pressedDown:clickCount:)]==NO) return;
-
- delegate = _delegate;
-}
-- (id) delegate {
- return delegate;
-}
-
-- (BOOL) simulateHoldEvent {
- return simulateHoldEvents;
-}
-- (void) setSimulateHoldEvent: (BOOL) value {
- simulateHoldEvents = value;
-}
-
-- (BOOL) simulatesHoldForButtonIdentifier: (RemoteControlEventIdentifier) identifier remoteControl: (RemoteControl*) remoteControl {
- // we do that check only for the normal button identifiers as we would check for hold support for hold events instead
- if (identifier > (1 << EVENT_TO_HOLD_EVENT_OFFSET)) return NO;
-
- return [self simulateHoldEvent] && [remoteControl sendsEventForButtonIdentifier: (identifier << EVENT_TO_HOLD_EVENT_OFFSET)]==NO;
-}
-
-- (BOOL) clickCountingEnabled {
- return clickCountEnabledButtons != 0;
-}
-- (void) setClickCountingEnabled: (BOOL) value {
- if (value) {
- [self setClickCountEnabledButtons: kRemoteButtonPlus | kRemoteButtonMinus | 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;
-}
-
-- (void) sendSimulatedHoldEvent: (id) time {
- BOOL startSimulateHold = NO;
- RemoteControlEventIdentifier event = lastHoldEvent;
- @synchronized(self) {
- startSimulateHold = (lastHoldEvent>0 && lastHoldEventTime == [time doubleValue]);
- }
- if (startSimulateHold) {
- lastEventSimulatedHold = YES;
- event = (event << EVENT_TO_HOLD_EVENT_OFFSET);
- [delegate remoteButton:event pressedDown: YES clickCount: 1];
- }
-}
-
-- (void) executeClickCountEvent: (NSArray*) values {
- RemoteControlEventIdentifier 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;
- lastClickCountEvent = 0;
- lastClickCountEventTime = 0;
- }
- }
-
- if (finishedClicking) {
- [delegate remoteButton:event pressedDown: YES clickCount:finalClickCount];
- // trigger a button release event, too
- [NSThread sleepUntilDate: [NSDate dateWithTimeIntervalSinceNow:0.1]];
- [delegate remoteButton:event pressedDown: NO clickCount:finalClickCount];
- }
-}
-
-- (void) sendRemoteButtonEvent: (RemoteControlEventIdentifier) event pressedDown: (BOOL) pressedDown remoteControl: (RemoteControl*) remoteControl {
- if (!delegate) return;
-
- BOOL clickCountingForEvent = ([self clickCountEnabledButtons] & event) == event;
-
- if ([self simulatesHoldForButtonIdentifier: event remoteControl: remoteControl] && lastClickCountEvent==0) {
- if (pressedDown) {
- // wait to see if it is a hold
- lastHoldEvent = event;
- lastHoldEventTime = [NSDate timeIntervalSinceReferenceDate];
- [self performSelector:@selector(sendSimulatedHoldEvent:)
- withObject:[NSNumber numberWithDouble:lastHoldEventTime]
- afterDelay:HOLD_RECOGNITION_TIME_INTERVAL];
- return;
- } else {
- if (lastEventSimulatedHold) {
- // it was a hold
- // send an event for "hold release"
- event = (event << EVENT_TO_HOLD_EVENT_OFFSET);
- lastHoldEvent = 0;
- lastEventSimulatedHold = NO;
-
- [delegate remoteButton:event pressedDown: pressedDown clickCount:1];
- return;
- } else {
- RemoteControlEventIdentifier previousEvent = lastHoldEvent;
- @synchronized(self) {
- lastHoldEvent = 0;
- }
-
- // in case click counting is enabled we have to setup the state for that, too
- if (clickCountingForEvent) {
- lastClickCountEvent = previousEvent;
- lastClickCountEventTime = lastHoldEventTime;
- NSNumber* eventNumber;
- NSNumber* timeNumber;
- eventClickCount = 1;
- timeNumber = [NSNumber numberWithDouble:lastClickCountEventTime];
- eventNumber= [NSNumber numberWithUnsignedInt:previousEvent];
- NSTimeInterval diffTime = maxClickTimeDifference-([NSDate timeIntervalSinceReferenceDate]-lastHoldEventTime);
- [self performSelector: @selector(executeClickCountEvent:)
- withObject: [NSArray arrayWithObjects:eventNumber, timeNumber, nil]
- afterDelay: diffTime];
- // we do not return here because we are still in the press-release event
- // that will be consumed below
- } else {
- // trigger the pressed down event that we consumed first
- [delegate remoteButton:event pressedDown: YES clickCount:1];
- }
- }
- }
- }
-
- if (clickCountingForEvent) {
- if (pressedDown == NO) return;
-
- 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 remoteButton:event pressedDown: pressedDown clickCount:1];
- }
-
-}
-
-@end
diff --git a/tools/EventClients/Clients/OSXRemote/RemoteControlWrapper/RemoteControl.h b/tools/EventClients/Clients/OSXRemote/RemoteControlWrapper/RemoteControl.h
deleted file mode 100644
index 34e9d5e19d..0000000000
--- a/tools/EventClients/Clients/OSXRemote/RemoteControlWrapper/RemoteControl.h
+++ /dev/null
@@ -1,102 +0,0 @@
-/*****************************************************************************
- * RemoteControl.h
- * RemoteControlWrapper
- *
- * Created by Martin Kahr on 11.03.06 under a MIT-style license.
- * Copyright (c) 2006 martinkahr.com. All rights reserved.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included
- * in all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- *
- *****************************************************************************/
-
-#import <Cocoa/Cocoa.h>
-
-// notifaction names that are being used to signal that an application wants to
-// have access to the remote control device or if the application has finished
-// using the remote control device
-extern NSString* REQUEST_FOR_REMOTE_CONTROL_NOTIFCATION;
-extern NSString* FINISHED_USING_REMOTE_CONTROL_NOTIFICATION;
-
-// keys used in user objects for distributed notifications
-extern NSString* kRemoteControlDeviceName;
-extern NSString* kApplicationIdentifier;
-extern NSString* kTargetApplicationIdentifier;
-
-// we have a 6 bit offset to make a hold event out of a normal event
-#define EVENT_TO_HOLD_EVENT_OFFSET 6
-
-@class RemoteControl;
-
-typedef enum _RemoteControlEventIdentifier {
- // normal events
- kRemoteButtonPlus =1<<1,
- kRemoteButtonMinus =1<<2,
- kRemoteButtonMenu =1<<3,
- kRemoteButtonPlay =1<<4,
- kRemoteButtonRight =1<<5,
- kRemoteButtonLeft =1<<6,
-
- // hold events
- kRemoteButtonPlus_Hold =1<<7,
- kRemoteButtonMinus_Hold =1<<8,
- kRemoteButtonMenu_Hold =1<<9,
- kRemoteButtonPlay_Hold =1<<10,
- kRemoteButtonRight_Hold =1<<11,
- kRemoteButtonLeft_Hold =1<<12,
-
- // special events (not supported by all devices)
- kRemoteControl_Switched =1<<13,
-} RemoteControlEventIdentifier;
-
-@interface NSObject(RemoteControlDelegate)
-
-- (void) sendRemoteButtonEvent: (RemoteControlEventIdentifier) event pressedDown: (BOOL) pressedDown remoteControl: (RemoteControl*) remoteControl;
-
-@end
-
-/*
- Base Interface for Remote Control devices
- */
-@interface RemoteControl : NSObject {
- id delegate;
-}
-
-// returns nil if the remote control device is not available
-- (id) initWithDelegate: (id) remoteControlDelegate;
-
-- (void) setListeningToRemote: (BOOL) value;
-- (BOOL) isListeningToRemote;
-
-- (BOOL) isOpenInExclusiveMode;
-- (void) setOpenInExclusiveMode: (BOOL) value;
-
-- (IBAction) startListening: (id) sender;
-- (IBAction) stopListening: (id) sender;
-
-// is this remote control sending the given event?
-- (BOOL) sendsEventForButtonIdentifier: (RemoteControlEventIdentifier) identifier;
-
-// sending of notifications between applications
-+ (void) sendFinishedNotifcationForAppIdentifier: (NSString*) identifier;
-+ (void) sendRequestForRemoteControlNotification;
-
-// name of the device
-+ (const char*) remoteControlDeviceName;
-
-@end
diff --git a/tools/EventClients/Clients/OSXRemote/RemoteControlWrapper/RemoteControl.m b/tools/EventClients/Clients/OSXRemote/RemoteControlWrapper/RemoteControl.m
deleted file mode 100644
index bf224dd1d8..0000000000
--- a/tools/EventClients/Clients/OSXRemote/RemoteControlWrapper/RemoteControl.m
+++ /dev/null
@@ -1,102 +0,0 @@
-/*****************************************************************************
- * RemoteControl.m
- * RemoteControlWrapper
- *
- * Created by Martin Kahr on 11.03.06 under a MIT-style license.
- * Copyright (c) 2006 martinkahr.com. All rights reserved.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included
- * in all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- *
- *****************************************************************************/
-
-#import "RemoteControl.h"
-
-// notifaction names that are being used to signal that an application wants to
-// have access to the remote control device or if the application has finished
-// using the remote control device
-NSString* REQUEST_FOR_REMOTE_CONTROL_NOTIFCATION = @"mac.remotecontrols.RequestForRemoteControl";
-NSString* FINISHED_USING_REMOTE_CONTROL_NOTIFICATION = @"mac.remotecontrols.FinishedUsingRemoteControl";
-
-// keys used in user objects for distributed notifications
-NSString* kRemoteControlDeviceName = @"RemoteControlDeviceName";
-NSString* kApplicationIdentifier = @"CFBundleIdentifier";
-// bundle identifier of the application that should get access to the remote control
-// this key is being used in the FINISHED notification only
-NSString* kTargetApplicationIdentifier = @"TargetBundleIdentifier";
-
-
-@implementation RemoteControl
-
-// returns nil if the remote control device is not available
-- (id) initWithDelegate: (id) _remoteControlDelegate {
- if (self = [super init]) {
- delegate = _remoteControlDelegate;
- }
- return self;
-}
-
-- (void) dealloc {
- [super dealloc];
-}
-
-- (void) setListeningToRemote: (BOOL) value {
-}
-- (BOOL) isListeningToRemote {
- return NO;
-}
-
-- (IBAction) startListening: (id) sender {
-}
-- (IBAction) stopListening: (id) sender {
-
-}
-
-- (BOOL) isOpenInExclusiveMode {
- return YES;
-}
-- (void) setOpenInExclusiveMode: (BOOL) value {
-}
-
-- (BOOL) sendsEventForButtonIdentifier: (RemoteControlEventIdentifier) identifier {
- return YES;
-}
-
-+ (void) sendDistributedNotification: (NSString*) notificationName targetBundleIdentifier: (NSString*) targetIdentifier {
- NSDictionary* userInfo = [NSDictionary dictionaryWithObjectsAndKeys: [NSString stringWithCString:[self remoteControlDeviceName] encoding:NSASCIIStringEncoding],
- kRemoteControlDeviceName, [[NSBundle mainBundle] bundleIdentifier], kApplicationIdentifier,
- targetIdentifier, kTargetApplicationIdentifier, nil];
-
- [[NSDistributedNotificationCenter defaultCenter] postNotificationName:notificationName
- object:nil
- userInfo:userInfo
- deliverImmediately:YES];
-}
-
-+ (void) sendFinishedNotifcationForAppIdentifier: (NSString*) identifier {
- [self sendDistributedNotification:FINISHED_USING_REMOTE_CONTROL_NOTIFICATION targetBundleIdentifier:identifier];
-}
-+ (void) sendRequestForRemoteControlNotification {
- [self sendDistributedNotification:REQUEST_FOR_REMOTE_CONTROL_NOTIFCATION targetBundleIdentifier:nil];
-}
-
-+ (const char*) remoteControlDeviceName {
- return NULL;
-}
-
-@end
diff --git a/tools/EventClients/Clients/OSXRemote/RemoteControlWrapper/RemoteControlContainer.h b/tools/EventClients/Clients/OSXRemote/RemoteControlWrapper/RemoteControlContainer.h
deleted file mode 100644
index e665ae1eab..0000000000
--- a/tools/EventClients/Clients/OSXRemote/RemoteControlWrapper/RemoteControlContainer.h
+++ /dev/null
@@ -1,38 +0,0 @@
-/*****************************************************************************
- * RemoteControlContainer.h
- * RemoteControlWrapper
- *
- * Created by Martin Kahr on 11.03.06 under a MIT-style license.
- * Copyright (c) 2006 martinkahr.com. All rights reserved.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included
- * in all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- *
- *****************************************************************************/
-
-#import <Cocoa/Cocoa.h>
-#import "RemoteControl.h"
-
-@interface RemoteControlContainer : RemoteControl {
- NSMutableArray* remoteControls;
-}
-
-- (BOOL) instantiateAndAddRemoteControlDeviceWithClass: (Class) clazz;
-- (unsigned int) count;
-
-@end
diff --git a/tools/EventClients/Clients/OSXRemote/RemoteControlWrapper/RemoteControlContainer.m b/tools/EventClients/Clients/OSXRemote/RemoteControlWrapper/RemoteControlContainer.m
deleted file mode 100644
index 8517ea733e..0000000000
--- a/tools/EventClients/Clients/OSXRemote/RemoteControlWrapper/RemoteControlContainer.m
+++ /dev/null
@@ -1,114 +0,0 @@
-/*****************************************************************************
- * RemoteControlContainer.m
- * RemoteControlWrapper
- *
- * Created by Martin Kahr on 11.03.06 under a MIT-style license.
- * Copyright (c) 2006 martinkahr.com. All rights reserved.
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included
- * in all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
- * THE SOFTWARE.
- *
- *****************************************************************************/
-
-#import "RemoteControlContainer.h"
-
-
-@implementation RemoteControlContainer
-
-- (id) initWithDelegate: (id) _remoteControlDelegate {
- if (self = [super initWithDelegate:_remoteControlDelegate]) {
- remoteControls = [[NSMutableArray alloc] init];
- }
- return self;
-}
-
-- (void) dealloc {
- [self stopListening: self];
- [remoteControls release];
- [super dealloc];
-}
-
-- (BOOL) instantiateAndAddRemoteControlDeviceWithClass: (Class) clazz {
- RemoteControl* remoteControl = [[clazz alloc] initWithDelegate: delegate];
- if (remoteControl) {
- [remoteControls addObject: remoteControl];
- [remoteControl addObserver: self forKeyPath:@"listeningToRemote" options:NSKeyValueObservingOptionNew context:nil];
- return YES;
- }
- return NO;
-}
-
-- (unsigned int) count {
- return [remoteControls count];
-}
-
-- (void) reset {
- [self willChangeValueForKey:@"listeningToRemote"];
- [self didChangeValueForKey:@"listeningToRemote"];
-}
-
-- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
- [self reset];
-}
-
-- (void) setListeningToRemote: (BOOL) value {
- int i;
- for(i=0; i < [remoteControls count]; i++) {
- [[remoteControls objectAtIndex: i] setListeningToRemote: value];
- }
- if (value && value != [self isListeningToRemote]) [self performSelector:@selector(reset) withObject:nil afterDelay:0.01];
-}
-- (BOOL) isListeningToRemote {
- int i;
- for(i=0; i < [remoteControls count]; i++) {
- if ([[remoteControls objectAtIndex: i] isListeningToRemote]) {
- return YES;
- }
- }
- return NO;
-}
-
-- (IBAction) startListening: (id) sender {
- int i;
- for(i=0; i < [remoteControls count]; i++) {
- [[remoteControls objectAtIndex: i] startListening: sender];
- }
-}
-- (IBAction) stopListening: (id) sender {
- int i;
- for(i=0; i < [remoteControls count]; i++) {
- [[remoteControls objectAtIndex: i] stopListening: sender];
- }
-}
-
-- (BOOL) isOpenInExclusiveMode {
- BOOL mode = YES;
- int i;
- for(i=0; i < [remoteControls count]; i++) {
- mode = mode && ([[remoteControls objectAtIndex: i] isOpenInExclusiveMode]);
- }
- return mode;
-}
-- (void) setOpenInExclusiveMode: (BOOL) value {
- int i;
- for(i=0; i < [remoteControls count]; i++) {
- [[remoteControls objectAtIndex: i] setOpenInExclusiveMode:value];
- }
-}
-
-@end
diff --git a/tools/EventClients/Clients/OSXRemote/XBMCHelper.h b/tools/EventClients/Clients/OSXRemote/XBMCHelper.h
index 4d69a91e19..7f6ae5cdb9 100644
--- a/tools/EventClients/Clients/OSXRemote/XBMCHelper.h
+++ b/tools/EventClients/Clients/OSXRemote/XBMCHelper.h
@@ -8,11 +8,10 @@
#import <Cocoa/Cocoa.h>
#import "xbmcclientwrapper.h"
+#import "HIDRemote.h"
-@class AppleRemote, MultiClickRemoteBehavior;
-
-@interface XBMCHelper : NSObject {
- AppleRemote* mp_remote_control;
+@interface XBMCHelper : NSObject<HIDRemoteDelegate> {
+ HIDRemote *remote;
XBMCClientWrapper* mp_wrapper;
NSString* mp_app_path;
NSString* mp_home_path;
diff --git a/tools/EventClients/Clients/OSXRemote/XBMCHelper.m b/tools/EventClients/Clients/OSXRemote/XBMCHelper.m
index 19c67ca5c6..3bc68cbc1c 100644
--- a/tools/EventClients/Clients/OSXRemote/XBMCHelper.m
+++ b/tools/EventClients/Clients/OSXRemote/XBMCHelper.m
@@ -7,216 +7,297 @@
//
#import "XBMCHelper.h"
-#import "remotecontrolwrapper/AppleRemote.h"
#import "XBMCDebugHelpers.h"
+#import "HIDRemote.h"
//----------------------------------------------------------------------------
//----------------------------------------------------------------------------
+@interface XBMCHelper (private)
+
+- (NSString *)buttonNameForButtonCode:(HIDRemoteButtonCode)buttonCode;
+- (void) checkAndLaunchApp;
+
+@end
+
@implementation XBMCHelper
- (id) init{
PRINT_SIGNATURE();
- if( ![super init] ){
- return nil;
- }
- mp_wrapper = nil;
- mp_remote_control = [[[AppleRemote alloc] initWithDelegate: self] retain];
- [mp_remote_control setProcessesBacklog:true];
- [mp_remote_control setOpenInExclusiveMode:true];
- if( ! mp_remote_control ){
- NSException* myException = [NSException
- exceptionWithName:@"AppleRemoteInitExecption"
- reason:@"AppleRemote could not be initialized"
- userInfo:nil];
- @throw myException;
- }
- [mp_remote_control startListening: self];
- if(![mp_remote_control isListeningToRemote]){
- ELOG(@"Warning: XBMCHelper could not open the IR-Device in exclusive mode. Other remote control apps running?");
+ if( (self = [super init]) ){
+ if ((remote = [HIDRemote sharedHIDRemote]))
+ {
+ [remote setDelegate:self];
+ [remote setSimulateHoldEvents:NO];
+ //for now, we're using lending of exlusive lock
+ //kHIDRemoteModeExclusiveAuto isn't working, as we're a background daemon
+ //one possibility would be to know when XBMC is running. Once we know that,
+ //we could aquire exclusive lock when it's running, and release _exclusive_
+ //access once done
+ [remote setExclusiveLockLendingEnabled:YES];
+
+ if ([HIDRemote isCandelairInstallationRequiredForRemoteMode:kHIDRemoteModeExclusive])
+ {
+ //setup failed. user needs to install CandelaIR driver
+ NSLog(@"Error! Candelair driver installation necessary. XBMC Remote control won't function properly!");
+ NSLog(@"Due to an issue in the OS version you are running, an additional driver needs to be installed before XBMC(Helper) can reliably access the remote.");
+ NSLog(@"See http://www.candelair.com/download/ for details");
+ [super dealloc];
+ return nil;
+ }
+ else
+ {
+ if ([remote startRemoteControl:kHIDRemoteModeExclusiveAuto])
+ {
+ DLOG(@"Driver has started successfully.");
+ if ([remote activeRemoteControlCount])
+ DLOG(@"Driver has found %d remotes.", [remote activeRemoteControlCount]);
+ else
+ ELOG(@"Driver has not found any remotes it could use. Will use remotes as they become available.");
+ }
+ else
+ {
+ //setup failed, cleanup
+ [remote setDelegate:nil];
+ [super dealloc];
+ return nil;
+ }
+ }
+ }
}
return self;
}
+//----------------------------------------------------------------------------
- (void) dealloc{
PRINT_SIGNATURE();
- [mp_remote_control stopListening: self];
- [mp_remote_control release];
+ [remote stopRemoteControl];
[mp_wrapper release];
[mp_app_path release];
[mp_home_path release];
+
[super dealloc];
}
//----------------------------------------------------------------------------
-- (void) checkAndLaunchApp
-{
- if(!mp_app_path || ![mp_app_path length]){
- ELOG(@"No executable set. Nothing to launch");
- return;
- }
-
- NSFileManager *fileManager = [NSFileManager defaultManager];
- if(![fileManager fileExistsAtPath:mp_app_path]){
- ELOG(@"Path does not exist: %@. Cannot launch executable", mp_app_path);
- return;
- }
- if(mp_home_path && [mp_home_path length])
- setenv("XBMC_HOME", [mp_home_path cString], 1);
- //launch or activate xbmc
- if(![[NSWorkspace sharedWorkspace] launchApplication:mp_app_path]){
- ELOG(@"Error launching %@", mp_app_path);
+- (void) connectToServer:(NSString*) fp_server onPort:(int) f_port withMode:(eRemoteMode) f_mode withTimeout:(double) f_timeout{
+ if(mp_wrapper)
+ [self disconnect];
+ mp_wrapper = [[XBMCClientWrapper alloc] initWithMode:f_mode serverAddress:fp_server port:f_port verbose:m_verbose];
+ [mp_wrapper setUniversalModeTimeout:f_timeout];
+}
+
+//----------------------------------------------------------------------------
+- (void) disconnect{
+ [mp_wrapper release];
+ mp_wrapper = nil;
+}
+
+//----------------------------------------------------------------------------
+- (void) enableVerboseMode:(bool) f_really{
+ m_verbose = f_really;
+ [mp_wrapper enableVerboseMode:f_really];
+}
+
+//----------------------------------------------------------------------------
+- (void) setApplicationPath:(NSString*) fp_app_path{
+ if (mp_app_path != fp_app_path) {
+ [mp_app_path release];
+ mp_app_path = [[fp_app_path stringByStandardizingPath] retain];
}
}
//----------------------------------------------------------------------------
-- (void) sendRemoteButtonEvent: (RemoteControlEventIdentifier) event pressedDown: (BOOL) pressedDown remoteControl: (RemoteControl*) remoteControl;
+- (void) setApplicationHome:(NSString*) fp_home_path{
+ if (mp_home_path != fp_home_path) {
+ [mp_home_path release];
+ mp_home_path = [[fp_home_path stringByStandardizingPath] retain];
+ }
+}
+
+#pragma mark -
+#pragma mark HIDRemote delegate methods
+
+// Notification of button events
+- (void)hidRemote:(HIDRemote *)hidRemote // The instance of HIDRemote sending this
+ eventWithButton:(HIDRemoteButtonCode)buttonCode // Event for the button specified by code
+ isPressed:(BOOL)isPressed // The button was pressed (YES) / released (NO)
{
- if(m_verbose) {
- //do some logging here
- //[self logButton: event press;
+ if(m_verbose){
+ NSLog(@"Received button '%@' %@ event", [self buttonNameForButtonCode:buttonCode], (isPressed)?@"press":@"release");
}
-
- switch(event){
- case kRemoteButtonPlay:
- if(pressedDown) [mp_wrapper handleEvent:ATV_BUTTON_PLAY];
- break;
- case kRemoteButtonPlay_Hold:
- if(pressedDown) [mp_wrapper handleEvent:ATV_BUTTON_PLAY_H];
- break;
- case kRemoteButtonRight:
- if(pressedDown)
- [mp_wrapper handleEvent:ATV_BUTTON_RIGHT];
+ switch(buttonCode)
+ {
+ case kHIDRemoteButtonCodePlus:
+ if(isPressed)
+ [mp_wrapper handleEvent:ATV_BUTTON_UP];
else
- [mp_wrapper handleEvent:ATV_BUTTON_RIGHT_RELEASE];
+ [mp_wrapper handleEvent:ATV_BUTTON_UP_RELEASE];
break;
- case kRemoteButtonRight_Hold:
- if(pressedDown)
- [mp_wrapper handleEvent:ATV_BUTTON_RIGHT_H];
+ case kHIDRemoteButtonCodeMinus:
+ if(isPressed)
+ [mp_wrapper handleEvent:ATV_BUTTON_DOWN];
else
- [mp_wrapper handleEvent:ATV_BUTTON_RIGHT_H_RELEASE];
+ [mp_wrapper handleEvent:ATV_BUTTON_DOWN_RELEASE];
break;
- case kRemoteButtonLeft:
- if(pressedDown)
+ case kHIDRemoteButtonCodeLeft:
+ if(isPressed)
[mp_wrapper handleEvent:ATV_BUTTON_LEFT];
else
[mp_wrapper handleEvent:ATV_BUTTON_LEFT_RELEASE];
break;
- case kRemoteButtonLeft_Hold:
- if(pressedDown)
+ case kHIDRemoteButtonCodeLeftHold:
+ if(isPressed)
[mp_wrapper handleEvent:ATV_BUTTON_LEFT_H];
else
[mp_wrapper handleEvent:ATV_BUTTON_LEFT_H_RELEASE];
break;
- case kRemoteButtonPlus:
- if(pressedDown)
- [mp_wrapper handleEvent:ATV_BUTTON_UP];
+ case kHIDRemoteButtonCodeRight:
+ if(isPressed)
+ [mp_wrapper handleEvent:ATV_BUTTON_RIGHT];
else
- [mp_wrapper handleEvent:ATV_BUTTON_UP_RELEASE];
+ [mp_wrapper handleEvent:ATV_BUTTON_RIGHT_RELEASE];
break;
- case kRemoteButtonMinus:
- if(pressedDown)
- [mp_wrapper handleEvent:ATV_BUTTON_DOWN];
+ case kHIDRemoteButtonCodeRightHold:
+ if(isPressed)
+ [mp_wrapper handleEvent:ATV_BUTTON_RIGHT_H];
else
- [mp_wrapper handleEvent:ATV_BUTTON_DOWN_RELEASE];
- break;
- case kRemoteButtonMenu:
- if(pressedDown){
- [self checkAndLaunchApp]; //launch mp_app_path if it's not running
+ [mp_wrapper handleEvent:ATV_BUTTON_RIGHT_H_RELEASE];
+ break;
+ case kHIDRemoteButtonCodePlayPause:
+ if(isPressed) [mp_wrapper handleEvent:ATV_BUTTON_PLAY];
+ break;
+ case kHIDRemoteButtonCodePlayPauseHold:
+ if(isPressed) [mp_wrapper handleEvent:ATV_BUTTON_PLAY_H];
+ break;
+ case kHIDRemoteButtonCodeMenu:
+ if(isPressed){
[mp_wrapper handleEvent:ATV_BUTTON_MENU];
}
break;
- case kRemoteButtonMenu_Hold:
- if(pressedDown) [mp_wrapper handleEvent:ATV_BUTTON_MENU_H];
- break;
- case kRemoteControl_Switched:
- if(pressedDown) [mp_wrapper switchRemote: [mp_remote_control deviceID]];
- break;
+ case kHIDRemoteButtonCodeMenuHold:
+ if(isPressed) {
+ [self checkAndLaunchApp]; //launch mp_app_path if it's not running
+ [mp_wrapper handleEvent:ATV_BUTTON_MENU_H];
+ }
+ break;
default:
- NSLog(@"Oha, remote button not recognized %i pressed/released %i", event, pressedDown);
+ NSLog(@"Oha, remote button not recognized %i pressed/released %i", buttonCode, isPressed);
}
}
-//----------------------------------------------------------------------------
-- (void) connectToServer:(NSString*) fp_server onPort:(int) f_port withMode:(eRemoteMode) f_mode withTimeout:(double) f_timeout{
- if(mp_wrapper)
- [self disconnect];
- mp_wrapper = [[XBMCClientWrapper alloc] initWithMode:f_mode serverAddress:fp_server port:f_port verbose:m_verbose];
- [mp_wrapper setUniversalModeTimeout:f_timeout];
-}
-//----------------------------------------------------------------------------
-- (void) disconnect{
- [mp_wrapper release];
- mp_wrapper = nil;
+// Notification of ID changes
+- (void)hidRemote:(HIDRemote *)hidRemote
+remoteIDChangedOldID:(SInt32)old // Invoked when the user switched to a remote control with a different ID
+ newID:(SInt32)newID
+{
+ if(m_verbose)
+ NSLog(@"Change of remote ID from %d to %d", old, newID);
+ [mp_wrapper switchRemote: newID];
}
-//----------------------------------------------------------------------------
-- (void) enableVerboseMode:(bool) f_really{
- m_verbose = f_really;
- [mp_wrapper enableVerboseMode:f_really];
-}
+#pragma mark -
+#pragma mark Helper methods
-//----------------------------------------------------------------------------
-- (void) setApplicationPath:(NSString*) fp_app_path{
- if (mp_app_path != fp_app_path) {
- [mp_app_path release];
- mp_app_path = [[fp_app_path stringByStandardizingPath] retain];
- }
+- (NSString *)buttonNameForButtonCode:(HIDRemoteButtonCode)buttonCode
+{
+ switch (buttonCode)
+ {
+ case kHIDRemoteButtonCodePlus:
+ return (@"Plus");
+ break;
+ case kHIDRemoteButtonCodeMinus:
+ return (@"Minus");
+ break;
+ case kHIDRemoteButtonCodeLeft:
+ return (@"Left");
+ break;
+ case kHIDRemoteButtonCodeRight:
+ return (@"Right");
+ break;
+ case kHIDRemoteButtonCodePlayPause:
+ return (@"Play/Pause");
+ break;
+ case kHIDRemoteButtonCodeMenu:
+ return (@"Menu");
+ break;
+ case kHIDRemoteButtonCodePlusHold:
+ return (@"Plus (hold)");
+ break;
+ case kHIDRemoteButtonCodeMinusHold:
+ return (@"Minus (hold)");
+ break;
+ case kHIDRemoteButtonCodeLeftHold:
+ return (@"Left (hold)");
+ break;
+ case kHIDRemoteButtonCodeRightHold:
+ return (@"Right (hold)");
+ break;
+ case kHIDRemoteButtonCodePlayPauseHold:
+ return (@"Play/Pause (hold)");
+ break;
+ case kHIDRemoteButtonCodeMenuHold:
+ return (@"Menu (hold)");
+ break;
+ }
+ return ([NSString stringWithFormat:@"Button %x", (int)buttonCode]);
}
//----------------------------------------------------------------------------
-- (void) setApplicationHome:(NSString*) fp_home_path{
- if (mp_home_path != fp_home_path) {
- [mp_home_path release];
- mp_home_path = [[fp_home_path stringByStandardizingPath] retain];
+- (void) checkAndLaunchApp
+{
+ if(!mp_app_path || ![mp_app_path length]){
+ ELOG(@"No executable set. Nothing to launch");
+ return;
}
+ NSFileManager *fileManager = [NSFileManager defaultManager];
+ if([fileManager fileExistsAtPath:mp_app_path]){
+ if(mp_home_path && [mp_home_path length])
+ setenv("XBMC_HOME", [mp_home_path cString], 1);
+ //launch or activate xbmc
+ if(![[NSWorkspace sharedWorkspace] launchApplication:mp_app_path])
+ ELOG(@"Error launching %@", mp_app_path);
+ } else
+ ELOG(@"Path does not exist: %@. Cannot launch executable", mp_app_path);
}
-// NSString* pressed;
-// NSString* buttonName;
-// if (pressedDown) pressed = @"(pressed)"; else pressed = @"(released)";
-//
-// switch(event) {
-// case kRemoteButtonPlus:
-// buttonName = @"Volume up";
-// break;
-// case kRemoteButtonMinus:
-// buttonName = @"Volume down";
-// break;
-// case kRemoteButtonMenu:
-// buttonName = @"Menu";
-// break;
-// case kRemoteButtonPlay:
-// buttonName = @"Play";
-// break;
-// case kRemoteButtonRight:
-// buttonName = @"Right";
-// break;
-// case kRemoteButtonLeft:
-// buttonName = @"Left";
-// break;
-// case kRemoteButtonRight_Hold:
-// buttonName = @"Right holding";
-// break;
-// case kRemoteButtonLeft_Hold:
-// buttonName = @"Left holding";
-// break;
-// case kRemoteButtonPlus_Hold:
-// buttonName = @"Volume up holding";
-// break;
-// case kRemoteButtonMinus_Hold:
-// buttonName = @"Volume down holding";
-// break;
-// case kRemoteButtonPlay_Hold:
-// buttonName = @"Play (sleep mode)";
-// break;
-// case kRemoteButtonMenu_Hold:
-// buttonName = @"Menu holding";
-// break;
-// case kRemoteControl_Switched:
-// buttonName = @"Remote Control Switched";
-// break;
-// default:
-// break;
-// }
-// NSLog(@"%@ %@", pressed, buttonName);
-// }
+
+
+#pragma mark -
+#pragma mark Other (unused) HIDRemoteDelegate methods
+//- (BOOL)hidRemote:(HIDRemote *)aHidRemote
+//lendExclusiveLockToApplicationWithInfo:(NSDictionary *)applicationInfo
+//{
+// NSLog(@"Lending exclusive lock to %@ (pid %@)", [applicationInfo objectForKey:(id)kCFBundleIdentifierKey], [applicationInfo objectForKey:kHIDRemoteDNStatusPIDKey]);
+// return (YES);
+//}
+//
+//- (void)hidRemote:(HIDRemote *)aHidRemote
+//exclusiveLockReleasedByApplicationWithInfo:(NSDictionary *)applicationInfo
+//{
+// NSLog(@"Exclusive lock released by %@ (pid %@)", [applicationInfo objectForKey:(id)kCFBundleIdentifierKey], [applicationInfo objectForKey:kHIDRemoteDNStatusPIDKey]);
+// [aHidRemote startRemoteControl:kHIDRemoteModeExclusive];
+//}
+//
+//- (BOOL)hidRemote:(HIDRemote *)aHidRemote
+//shouldRetryExclusiveLockWithInfo:(NSDictionary *)applicationInfo
+//{
+// NSLog(@"%@ (pid %@) says I should retry to acquire exclusive locks", [applicationInfo objectForKey:(id)kCFBundleIdentifierKey], [applicationInfo objectForKey:kHIDRemoteDNStatusPIDKey]);
+// return (YES);
+//}
+//
+//
+//// Notification about hardware additions/removals
+//- (void)hidRemote:(HIDRemote *)aHidRemote foundNewHardwareWithAttributes:(NSMutableDictionary *)attributes
+//{
+// NSLog(@"Found hardware: %@ by %@ (Transport: %@)", [attributes objectForKey:kHIDRemoteProduct], [attributes objectForKey:kHIDRemoteManufacturer], [attributes objectForKey:kHIDRemoteTransport]);
+//}
+//
+//- (void)hidRemote:(HIDRemote *)aHidRemote failedNewHardwareWithError:(NSError *)error
+//{
+// NSLog(@"Initialization of hardware failed with error %@ (%@)", [error localizedDescription], [[error userInfo] objectForKey:@"InternalErrorCode"]);
+//}
+//
+//- (void)hidRemote:(HIDRemote *)aHidRemote releasedHardwareWithAttributes:(NSMutableDictionary *)attributes
+//{
+// NSLog(@"Released hardware: %@ by %@ (Transport: %@)", [attributes objectForKey:kHIDRemoteProduct], [attributes objectForKey:kHIDRemoteManufacturer], [attributes objectForKey:kHIDRemoteTransport]);
+//}
@end
diff --git a/tools/EventClients/Clients/OSXRemote/XBMCHelper.xcodeproj/project.pbxproj b/tools/EventClients/Clients/OSXRemote/XBMCHelper.xcodeproj/project.pbxproj
index 0c6c5ef7c9..a3686c5ceb 100644
--- a/tools/EventClients/Clients/OSXRemote/XBMCHelper.xcodeproj/project.pbxproj
+++ b/tools/EventClients/Clients/OSXRemote/XBMCHelper.xcodeproj/project.pbxproj
@@ -7,16 +7,9 @@
objects = {
/* Begin PBXBuildFile section */
- E45F2B1C0F95191E007BCC0B /* IRKeyboardEmu.m in Sources */ = {isa = PBXBuildFile; fileRef = E45F2B1B0F95191E007BCC0B /* IRKeyboardEmu.m */; };
+ E424E22C10877D3700659D45 /* HIDRemote.m in Sources */ = {isa = PBXBuildFile; fileRef = E424E22B10877D3700659D45 /* HIDRemote.m */; };
E4E62F370F83DB760066AF9D /* xbmchelper_main.mm in Sources */ = {isa = PBXBuildFile; fileRef = E4E62F340F83DB760066AF9D /* xbmchelper_main.mm */; };
E4E62F380F83DB760066AF9D /* XBMCHelper.m in Sources */ = {isa = PBXBuildFile; fileRef = E4E62F360F83DB760066AF9D /* XBMCHelper.m */; };
- E4E62F4A0F83DB830066AF9D /* AppleRemote.m in Sources */ = {isa = PBXBuildFile; fileRef = E4E62F3D0F83DB830066AF9D /* AppleRemote.m */; };
- E4E62F4B0F83DB830066AF9D /* GlobalKeyboardDevice.m in Sources */ = {isa = PBXBuildFile; fileRef = E4E62F3F0F83DB830066AF9D /* GlobalKeyboardDevice.m */; };
- E4E62F4C0F83DB830066AF9D /* HIDRemoteControlDevice.m in Sources */ = {isa = PBXBuildFile; fileRef = E4E62F410F83DB830066AF9D /* HIDRemoteControlDevice.m */; };
- E4E62F4D0F83DB830066AF9D /* KeyspanFrontRowControl.m in Sources */ = {isa = PBXBuildFile; fileRef = E4E62F430F83DB830066AF9D /* KeyspanFrontRowControl.m */; };
- E4E62F4E0F83DB830066AF9D /* MultiClickRemoteBehavior.m in Sources */ = {isa = PBXBuildFile; fileRef = E4E62F450F83DB830066AF9D /* MultiClickRemoteBehavior.m */; };
- E4E62F4F0F83DB830066AF9D /* RemoteControl.m in Sources */ = {isa = PBXBuildFile; fileRef = E4E62F470F83DB830066AF9D /* RemoteControl.m */; };
- E4E62F500F83DB830066AF9D /* RemoteControlContainer.m in Sources */ = {isa = PBXBuildFile; fileRef = E4E62F490F83DB830066AF9D /* RemoteControlContainer.m */; };
E4E62F600F83FB8C0066AF9D /* IOKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E4E62F5F0F83FB8C0066AF9D /* IOKit.framework */; };
E4E62F690F83FBB40066AF9D /* Carbon.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E4E62F680F83FBB40066AF9D /* Carbon.framework */; };
E4E62FD40F83FD7C0066AF9D /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E4E62FD30F83FD7C0066AF9D /* Cocoa.framework */; };
@@ -38,25 +31,12 @@
/* Begin PBXFileReference section */
09AB6884FE841BABC02AAC07 /* CoreFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreFoundation.framework; path = /System/Library/Frameworks/CoreFoundation.framework; sourceTree = "<absolute>"; };
8DD76F7E0486A8DE00D96B5E /* XBMCHelper */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = XBMCHelper; sourceTree = BUILT_PRODUCTS_DIR; };
- E45F2B1A0F95191E007BCC0B /* IRKeyboardEmu.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IRKeyboardEmu.h; sourceTree = "<group>"; };
- E45F2B1B0F95191E007BCC0B /* IRKeyboardEmu.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = IRKeyboardEmu.m; sourceTree = "<group>"; };
+ E424E22A10877D3700659D45 /* HIDRemote.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HIDRemote.h; sourceTree = "<group>"; };
+ E424E22B10877D3700659D45 /* HIDRemote.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HIDRemote.m; sourceTree = "<group>"; };
+ E424E23710877D5400659D45 /* Makefile.in */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = Makefile.in; sourceTree = "<group>"; };
E4E62F340F83DB760066AF9D /* xbmchelper_main.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = xbmchelper_main.mm; sourceTree = "<group>"; };
E4E62F350F83DB760066AF9D /* XBMCHelper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = XBMCHelper.h; sourceTree = "<group>"; };
E4E62F360F83DB760066AF9D /* XBMCHelper.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = XBMCHelper.m; sourceTree = "<group>"; };
- E4E62F3C0F83DB830066AF9D /* AppleRemote.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppleRemote.h; sourceTree = "<group>"; };
- E4E62F3D0F83DB830066AF9D /* AppleRemote.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppleRemote.m; sourceTree = "<group>"; };
- E4E62F3E0F83DB830066AF9D /* GlobalKeyboardDevice.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GlobalKeyboardDevice.h; sourceTree = "<group>"; };
- E4E62F3F0F83DB830066AF9D /* GlobalKeyboardDevice.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GlobalKeyboardDevice.m; sourceTree = "<group>"; };
- E4E62F400F83DB830066AF9D /* HIDRemoteControlDevice.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HIDRemoteControlDevice.h; sourceTree = "<group>"; };
- E4E62F410F83DB830066AF9D /* HIDRemoteControlDevice.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HIDRemoteControlDevice.m; sourceTree = "<group>"; };
- E4E62F420F83DB830066AF9D /* KeyspanFrontRowControl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = KeyspanFrontRowControl.h; sourceTree = "<group>"; };
- E4E62F430F83DB830066AF9D /* KeyspanFrontRowControl.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = KeyspanFrontRowControl.m; sourceTree = "<group>"; };
- E4E62F440F83DB830066AF9D /* MultiClickRemoteBehavior.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MultiClickRemoteBehavior.h; sourceTree = "<group>"; };
- E4E62F450F83DB830066AF9D /* MultiClickRemoteBehavior.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MultiClickRemoteBehavior.m; sourceTree = "<group>"; };
- E4E62F460F83DB830066AF9D /* RemoteControl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RemoteControl.h; sourceTree = "<group>"; };
- E4E62F470F83DB830066AF9D /* RemoteControl.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RemoteControl.m; sourceTree = "<group>"; };
- E4E62F480F83DB830066AF9D /* RemoteControlContainer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RemoteControlContainer.h; sourceTree = "<group>"; };
- E4E62F490F83DB830066AF9D /* RemoteControlContainer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RemoteControlContainer.m; sourceTree = "<group>"; };
E4E62F5F0F83FB8C0066AF9D /* IOKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = IOKit.framework; path = System/Library/Frameworks/IOKit.framework; sourceTree = SDKROOT; };
E4E62F680F83FBB40066AF9D /* Carbon.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Carbon.framework; path = System/Library/Frameworks/Carbon.framework; sourceTree = SDKROOT; };
E4E62FD30F83FD7C0066AF9D /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = System/Library/Frameworks/Cocoa.framework; sourceTree = SDKROOT; };
@@ -83,6 +63,7 @@
08FB7794FE84155DC02AAC07 /* XBMCHelper */ = {
isa = PBXGroup;
children = (
+ E424E23710877D5400659D45 /* Makefile.in */,
08FB7795FE84155DC02AAC07 /* Source */,
C6859E96029091FE04C91782 /* Documentation */,
08FB779DFE84155DC02AAC07 /* External Frameworks and Libraries */,
@@ -97,7 +78,8 @@
08FB7795FE84155DC02AAC07 /* Source */ = {
isa = PBXGroup;
children = (
- E4E62F3B0F83DB830066AF9D /* RemoteControlWrapper */,
+ E424E22A10877D3700659D45 /* HIDRemote.h */,
+ E424E22B10877D3700659D45 /* HIDRemote.m */,
E4E630030F8406900066AF9D /* xbmcclient.h */,
E4E62F340F83DB760066AF9D /* xbmchelper_main.mm */,
E4E62F350F83DB760066AF9D /* XBMCHelper.h */,
@@ -132,29 +114,6 @@
name = Documentation;
sourceTree = "<group>";
};
- E4E62F3B0F83DB830066AF9D /* RemoteControlWrapper */ = {
- isa = PBXGroup;
- children = (
- E4E62F3C0F83DB830066AF9D /* AppleRemote.h */,
- E4E62F3D0F83DB830066AF9D /* AppleRemote.m */,
- E4E62F3E0F83DB830066AF9D /* GlobalKeyboardDevice.h */,
- E4E62F3F0F83DB830066AF9D /* GlobalKeyboardDevice.m */,
- E4E62F400F83DB830066AF9D /* HIDRemoteControlDevice.h */,
- E4E62F410F83DB830066AF9D /* HIDRemoteControlDevice.m */,
- E4E62F420F83DB830066AF9D /* KeyspanFrontRowControl.h */,
- E4E62F430F83DB830066AF9D /* KeyspanFrontRowControl.m */,
- E4E62F440F83DB830066AF9D /* MultiClickRemoteBehavior.h */,
- E4E62F450F83DB830066AF9D /* MultiClickRemoteBehavior.m */,
- E4E62F460F83DB830066AF9D /* RemoteControl.h */,
- E4E62F470F83DB830066AF9D /* RemoteControl.m */,
- E4E62F480F83DB830066AF9D /* RemoteControlContainer.h */,
- E4E62F490F83DB830066AF9D /* RemoteControlContainer.m */,
- E45F2B1A0F95191E007BCC0B /* IRKeyboardEmu.h */,
- E45F2B1B0F95191E007BCC0B /* IRKeyboardEmu.m */,
- );
- path = RemoteControlWrapper;
- sourceTree = "<group>";
- };
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
@@ -200,15 +159,8 @@
files = (
E4E62F370F83DB760066AF9D /* xbmchelper_main.mm in Sources */,
E4E62F380F83DB760066AF9D /* XBMCHelper.m in Sources */,
- E4E62F4A0F83DB830066AF9D /* AppleRemote.m in Sources */,
- E4E62F4B0F83DB830066AF9D /* GlobalKeyboardDevice.m in Sources */,
- E4E62F4C0F83DB830066AF9D /* HIDRemoteControlDevice.m in Sources */,
- E4E62F4D0F83DB830066AF9D /* KeyspanFrontRowControl.m in Sources */,
- E4E62F4E0F83DB830066AF9D /* MultiClickRemoteBehavior.m in Sources */,
- E4E62F4F0F83DB830066AF9D /* RemoteControl.m in Sources */,
- E4E62F500F83DB830066AF9D /* RemoteControlContainer.m in Sources */,
E4E62FE80F83FDD90066AF9D /* xbmcclientwrapper.mm in Sources */,
- E45F2B1C0F95191E007BCC0B /* IRKeyboardEmu.m in Sources */,
+ E424E22C10877D3700659D45 /* HIDRemote.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
diff --git a/tools/EventClients/Clients/OSXRemote/xbmchelper_main.mm b/tools/EventClients/Clients/OSXRemote/xbmchelper_main.mm
index feb23473f1..55699821d7 100644
--- a/tools/EventClients/Clients/OSXRemote/xbmchelper_main.mm
+++ b/tools/EventClients/Clients/OSXRemote/xbmchelper_main.mm
@@ -21,7 +21,7 @@ bool g_verbose_mode = false;
//
const char* PROGNAME="XBMCHelper";
-const char* PROGVERS="0.5";
+const char* PROGVERS="0.6";
void ParseOptions(int argc, char** argv);
void ReadConfig();
@@ -199,19 +199,23 @@ int main (int argc, char * argv[]) {
NSLog(@"%s %s starting up...", PROGNAME, PROGVERS);
gp_xbmchelper = [[XBMCHelper alloc] init];
-
- signal(SIGHUP, Reconfigure);
- signal(SIGINT, Reconfigure);
- signal(SIGTERM, Reconfigure);
-
- ParseOptions(argc,argv);
- StartHelper();
-
- //run event loop in this thread
- RunCurrentEventLoop(kEventDurationForever);
- NSLog(@"%s %s exiting...", PROGNAME, PROGVERS);
- //cleanup
- [gp_xbmchelper release];
+ if(gp_xbmchelper){
+ signal(SIGHUP, Reconfigure);
+ signal(SIGINT, Reconfigure);
+ signal(SIGTERM, Reconfigure);
+
+ ParseOptions(argc,argv);
+ StartHelper();
+
+ //run event loop in this thread
+ RunCurrentEventLoop(kEventDurationForever);
+ NSLog(@"%s %s exiting...", PROGNAME, PROGVERS);
+ //cleanup
+ [gp_xbmchelper release];
+ } else {
+ NSLog(@"%s %s failed to initialize remote.", PROGNAME, PROGVERS);
+ return -1;
+ }
[pool drain];
return 0;
}