1 /*****************************************************************************
6 * Created by Martin Kahr on 11.03.06 under a MIT-style license.
7 * Copyright (c) 2006 martinkahr.com. All rights reserved.
9 * Permission is hereby granted, free of charge, to any person obtaining a
10 * copy of this software and associated documentation files (the "Software"),
11 * to deal in the Software without restriction, including without limitation
12 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
13 * and/or sell copies of the Software, and to permit persons to whom the
14 * Software is furnished to do so, subject to the following conditions:
16 * The above copyright notice and this permission notice shall be included
17 * in all copies or substantial portions of the Software.
19 * THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
22 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
27 *****************************************************************************
29 * Note that changes made by any members or contributors of the VideoLAN team
30 * (i.e. changes that were checked in exclusively into one of VideoLAN's source code
31 * repositories) are licensed under the GNU General Public License version 2,
32 * or (at your option) any later version.
33 * Thus, the following statements apply to our changes:
35 * Copyright (C) 2006-2007 VLC authors and VideoLAN
36 * Authors: Eric Petit <titer@m0k.org>
37 * Felix Kühne <fkuehne at videolan dot org>
39 * This program is free software; you can redistribute it and/or modify
40 * it under the terms of the GNU General Public License as published by
41 * the Free Software Foundation; either version 2 of the License, or
42 * (at your option) any later version.
44 * This program is distributed in the hope that it will be useful,
45 * but WITHOUT ANY WARRANTY; without even the implied warranty of
46 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
47 * GNU General Public License for more details.
49 * You should have received a copy of the GNU General Public License
50 * along with this program; if not, write to the Free Software
51 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
52 *****************************************************************************/
54 #import <Cocoa/Cocoa.h>
56 #import <mach/mach_error.h>
57 #import <IOKit/IOKitLib.h>
58 #import <IOKit/IOCFPlugIn.h>
59 #import <IOKit/hid/IOHIDLib.h>
60 #import <IOKit/hid/IOHIDKeys.h>
62 enum AppleRemoteEventIdentifier
64 kRemoteButtonVolume_Plus =1<<1,
65 kRemoteButtonVolume_Minus =1<<2,
66 kRemoteButtonMenu =1<<3,
67 kRemoteButtonPlay =1<<4,
68 kRemoteButtonRight =1<<5,
69 kRemoteButtonLeft =1<<6,
70 kRemoteButtonRight_Hold =1<<7,
71 kRemoteButtonLeft_Hold =1<<8,
72 kRemoteButtonMenu_Hold =1<<9,
73 kRemoteButtonPlay_Sleep =1<<10,
74 kRemoteControl_Switched =1<<11,
75 kRemoteButtonVolume_Plus_Hold =1<<12,
76 kRemoteButtonVolume_Minus_Hold =1<<13,
80 k2009RemoteButtonFullscreen
83 typedef enum AppleRemoteEventIdentifier AppleRemoteEventIdentifier;
85 /* Encapsulates usage of the apple remote control
86 This class is implemented as a singleton as there is exactly one remote per machine (until now)
87 The class is not thread safe
89 @interface AppleRemote : NSObject {
90 IOHIDDeviceInterface** hidDeviceInterface;
91 IOHIDQueueInterface** queue;
92 NSMutableArray* allCookies;
93 NSMutableDictionary* cookieToButtonMapping;
94 CFRunLoopSourceRef eventSource;
96 BOOL openInExclusiveMode;
97 BOOL simulatePlusMinusHold;
98 BOOL processesBacklog;
100 /* state for simulating plus/minus hold */
101 BOOL lastEventSimulatedHold;
102 AppleRemoteEventIdentifier lastPlusMinusEvent;
103 NSTimeInterval lastPlusMinusEventTime;
106 unsigned int clickCountEnabledButtons;
107 NSTimeInterval maxClickTimeDifference;
108 NSTimeInterval lastClickCountEventTime;
109 AppleRemoteEventIdentifier lastClickCountEvent;
110 unsigned int eventClickCount;
112 IBOutlet id delegate;
114 + (AppleRemote *)sharedInstance;
118 - (BOOL) isRemoteAvailable;
120 - (BOOL) isListeningToRemote;
121 - (void) setListeningToRemote: (BOOL) value;
123 - (BOOL) isOpenInExclusiveMode;
124 - (void) setOpenInExclusiveMode: (BOOL) value;
126 /* click counting makes it possible to recognize if the user has pressed a button repeatedly
127 * click counting does delay each event as it has to wait if there is another event (second click)
128 * therefore there is a slight time difference (maximumClickCountTimeDifference) between a single click
129 * of the user and the call of your delegate method
130 * click counting can be enabled individually for specific buttons. Use the property clickCountEnableButtons
131 * to set the buttons for which click counting shall be enabled */
132 - (BOOL) clickCountingEnabled;
133 - (void) setClickCountingEnabled: (BOOL) value;
135 - (unsigned int) clickCountEnabledButtons;
136 - (void) setClickCountEnabledButtons: (unsigned int)value;
138 /* the maximum time difference till which clicks are recognized as multi clicks */
139 - (NSTimeInterval) maximumClickCountTimeDifference;
140 - (void) setMaximumClickCountTimeDifference: (NSTimeInterval) timeDiff;
142 /* When your application needs to much time on the main thread when processing an event other events
143 * may already be received which are put on a backlog. As soon as your main thread
144 * has some spare time this backlog is processed and may flood your delegate with calls.
145 * Backlog processing is turned off by default. */
146 - (BOOL) processesBacklog;
147 - (void) setProcessesBacklog: (BOOL) value;
149 /* Sets an NSApplication delegate which starts listening when application is becoming active
150 * and stops listening when application resigns being active.
151 * If an NSApplication delegate has been already set all method calls will be forwarded to this delegate, too. */
152 - (BOOL) listeningOnAppActivate;
153 - (void) setListeningOnAppActivate: (BOOL) value;
155 /* Simulating plus/minus hold does deactivate sending of individual requests for plus/minus pressed down/released.
156 * Instead special hold events are being triggered when the user is pressing and holding plus/minus for a small period.
157 * With simulating enabled the plus/minus buttons do behave as the left/right buttons */
158 - (BOOL) simulatesPlusMinusHold;
159 - (void) setSimulatesPlusMinusHold: (BOOL) value;
161 /* Delegates are not retained */
162 - (void) setDelegate: (id) delegate;
165 - (IBAction) startListening: (id) sender;
166 - (IBAction) stopListening: (id) sender;
169 @interface AppleRemote (Singleton)
171 + (AppleRemote*) sharedRemote;
175 /* Method definitions for the delegate of the AppleRemote class */
176 @interface NSObject(NSAppleRemoteDelegate)
178 - (void) appleRemoteButton: (AppleRemoteEventIdentifier)buttonIdentifier pressedDown: (BOOL) pressedDown clickCount: (unsigned int) count;
182 @interface AppleRemote (PrivateMethods)
183 - (void) setRemoteId: (int) aValue;
184 - (NSDictionary*) cookieToButtonMapping;
185 - (IOHIDQueueInterface**) queue;
186 - (IOHIDDeviceInterface**) hidDeviceInterface;
187 - (void) handleEventWithCookieString: (NSString*) cookieString sumOfValues: (SInt32) sumOfValues;
190 @interface AppleRemote (IOKitMethods)
191 - (io_object_t) findAppleRemoteDevice;
192 - (IOHIDDeviceInterface**) createInterfaceForDevice: (io_object_t) hidDevice;
193 - (BOOL) initializeCookies;
197 /* A NSApplication delegate which is used to activate and deactivate listening to the remote control
198 * dependent on the activation state of your application.
199 * All events are delegated to the original NSApplication delegate if necessary */
200 @interface AppleRemoteApplicationDelegate : NSObject {
201 id applicationDelegate;
204 - (id) initWithApplicationDelegate: (id) delegate;
205 - (id) applicationDelegate;