kodi
HIDRemote.h
1 //
2 // HIDRemote.m
3 // HIDRemote V1.7 (5th September 2018)
4 //
5 // Created by Felix Schwarz on 06.04.07.
6 // Copyright 2007-2018 IOSPIRIT GmbH. All rights reserved.
7 //
8 // The latest version of this class is available at
9 // http://www.iospirit.com/developers/hidremote/
10 //
11 // ** LICENSE *************************************************************************
12 //
13 // Copyright (c) 2007-2017 IOSPIRIT GmbH (http://www.iospirit.com/)
14 // All rights reserved.
15 //
16 // Redistribution and use in source and binary forms, with or without modification,
17 // are permitted provided that the following conditions are met:
18 //
19 // * Redistributions of source code must retain the above copyright notice, this list
20 // of conditions and the following disclaimer.
21 //
22 // * Redistributions in binary form must reproduce the above copyright notice, this
23 // list of conditions and the following disclaimer in the documentation and/or other
24 // materials provided with the distribution.
25 //
26 // * Neither the name of IOSPIRIT GmbH nor the names of its contributors may be used to
27 // endorse or promote products derived from this software without specific prior
28 // written permission.
29 //
30 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
31 // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
32 // OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
33 // SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
34 // INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
35 // TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
36 // BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
37 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
38 // ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
39 // DAMAGE.
40 //
41 // ************************************************************************************
42 
43 // ************************************************************************************
44 // ********************************** DOCUMENTATION ***********************************
45 // ************************************************************************************
46 //
47 // - a reference is available at http://www.iospirit.com/developers/hidremote/reference/
48 // - for a guide, please see http://www.iospirit.com/developers/hidremote/guide/
49 //
50 // ************************************************************************************
51 
52 #import <Cocoa/Cocoa.h>
53 
54 // For legacy SDKs
55 #ifndef MAC_OS_X_VERSION_10_9
56 #define MAC_OS_X_VERSION_10_9 1090
57 #endif /* MAC_OS_X_VERSION_10_9 */
58 
59 #ifndef MAC_OS_X_VERSION_10_10
60 #define MAC_OS_X_VERSION_10_10 101000
61 #endif /* MAC_OS_X_VERSION_10_10 */
62 
63 #if MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_10
64 // Carbon is only required on OS X versions prior to 10.10 (for getting the OS version via Gestalt() -
65 // replaced by [[NSProcessInfo processInfo] operatingSystemVersion] in 10.10)
66 #include <Carbon/Carbon.h>
67 #endif
68 
69 #ifndef HIDREMOTE_THREADSAFETY_HARDENED_NOTIFICATION_HANDLING
70  #if MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5
71  // Enable thread-safe notification handling by default if deploying to OS X >= 10.5
72  #define HIDREMOTE_THREADSAFETY_HARDENED_NOTIFICATION_HANDLING 1
73  #else
74  #define HIDREMOTE_THREADSAFETY_HARDENED_NOTIFICATION_HANDLING 0
75  #endif
76 #endif
77 
78 #include <unistd.h>
79 #include <mach/mach.h>
80 #include <sys/types.h>
81 
82 #include <IOKit/IOKitLib.h>
83 #include <IOKit/IOCFPlugIn.h>
84 #include <IOKit/IOMessage.h>
85 #include <IOKit/hid/IOHIDKeys.h>
86 #include <IOKit/hid/IOHIDLib.h>
87 #include <IOKit/hid/IOHIDUsageTables.h>
88 #include <IOKit/hidsystem/IOHIDLib.h>
89 #include <IOKit/hidsystem/IOHIDParameter.h>
90 #include <IOKit/hidsystem/IOHIDShared.h>
91 
92 #pragma mark - Enums / Codes
93 
94 #ifndef HID_REMOTE_MODE_ENUM
95 #define HID_REMOTE_MODE_ENUM 1
96 typedef enum
97 {
98  kHIDRemoteModeNone = 0L,
99  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
100  // (RECOMMENDED ONLY FOR SPECIAL PURPOSES)
101 
102  kHIDRemoteModeExclusive, // Try to acquire an exclusive lock on the remote (NOT RECOMMENDED)
103 
104  kHIDRemoteModeExclusiveAuto // Try to acquire an exclusive lock on the remote whenever the application has focus. Temporarily release control over the
105  // remote when another application has focus (RECOMMENDED)
106 } HIDRemoteMode;
107 #endif /* HID_REMOTE_MODE_ENUM */
108 
109 typedef enum
110 {
111  /* A code reserved for "no button" (needed for tracking) */
112  kHIDRemoteButtonCodeNone = 0L,
113 
114  /* Standard codes - available for white plastic and aluminum remote */
115  kHIDRemoteButtonCodeUp,
116  kHIDRemoteButtonCodeDown,
117  kHIDRemoteButtonCodeLeft,
118  kHIDRemoteButtonCodeRight,
119  kHIDRemoteButtonCodeCenter,
120  kHIDRemoteButtonCodeMenu,
121 
122  /* Extra codes - Only available for the new aluminum version of the remote */
123  kHIDRemoteButtonCodePlay,
124 
125  /* Masks */
126  kHIDRemoteButtonCodeCodeMask = 0xFFL,
127  kHIDRemoteButtonCodeHoldMask = (1L << 16L),
128  kHIDRemoteButtonCodeSpecialMask = (1L << 17L),
129  kHIDRemoteButtonCodeAluminumMask = (1L << 21L), // PRIVATE - only used internally
130 
131  /* Hold button standard codes - available for white plastic and aluminum remote */
132  kHIDRemoteButtonCodeUpHold = (kHIDRemoteButtonCodeHoldMask|kHIDRemoteButtonCodeUp),
133  kHIDRemoteButtonCodeDownHold = (kHIDRemoteButtonCodeHoldMask|kHIDRemoteButtonCodeDown),
134  kHIDRemoteButtonCodeLeftHold = (kHIDRemoteButtonCodeHoldMask|kHIDRemoteButtonCodeLeft),
135  kHIDRemoteButtonCodeRightHold = (kHIDRemoteButtonCodeHoldMask|kHIDRemoteButtonCodeRight),
136  kHIDRemoteButtonCodeCenterHold = (kHIDRemoteButtonCodeHoldMask|kHIDRemoteButtonCodeCenter),
137  kHIDRemoteButtonCodeMenuHold = (kHIDRemoteButtonCodeHoldMask|kHIDRemoteButtonCodeMenu),
138 
139  /* Hold button extra codes - Only available for aluminum version of the remote */
140  kHIDRemoteButtonCodePlayHold = (kHIDRemoteButtonCodeHoldMask|kHIDRemoteButtonCodePlay),
141 
142  /* DEPRECATED codes - compatibility with HIDRemote 1.0 */
143  kHIDRemoteButtonCodePlus = kHIDRemoteButtonCodeUp,
144  kHIDRemoteButtonCodePlusHold = kHIDRemoteButtonCodeUpHold,
145  kHIDRemoteButtonCodeMinus = kHIDRemoteButtonCodeDown,
146  kHIDRemoteButtonCodeMinusHold = kHIDRemoteButtonCodeDownHold,
147  kHIDRemoteButtonCodePlayPause = kHIDRemoteButtonCodeCenter,
148  kHIDRemoteButtonCodePlayPauseHold = kHIDRemoteButtonCodeCenterHold,
149 
150  /* Special purpose codes */
151  kHIDRemoteButtonCodeIDChanged = (kHIDRemoteButtonCodeSpecialMask|(1L << 18L)), // (the ID of the connected remote has changed, you can safely ignore this)
152  #ifdef _HIDREMOTE_EXTENSIONS
153  #define _HIDREMOTE_EXTENSIONS_SECTION 1
154  #include "HIDRemoteAdditions.h"
155  #undef _HIDREMOTE_EXTENSIONS_SECTION
156  #endif /* _HIDREMOTE_EXTENSIONS */
157 } HIDRemoteButtonCode;
158 
159 typedef enum
160 {
161  kHIDRemoteModelUndetermined = 0L, // Assume a white plastic remote
162  kHIDRemoteModelWhitePlastic, // Signal *likely* to be coming from a white plastic remote
163  kHIDRemoteModelAluminum // Signal *definitely* coming from an aluminum remote
164 } HIDRemoteModel;
165 
166 typedef enum
167 {
168  kHIDRemoteAluminumRemoteSupportLevelNone = 0L, // This system has no support for the Aluminum Remote at all
169  kHIDRemoteAluminumRemoteSupportLevelEmulation, // This system possibly has support for the Aluminum Remote (via emulation)
170  kHIDRemoteAluminumRemoteSupportLevelNative // This system has native support for the Aluminum Remote
171 } HIDRemoteAluminumRemoteSupportLevel;
172 
173 @class HIDRemote;
174 
175 #pragma mark - Delegate protocol (mandatory)
177 
178 // Notification of button events
179 - (void)hidRemote:(HIDRemote *)hidRemote // The instance of HIDRemote sending this
180  eventWithButton:(HIDRemoteButtonCode)buttonCode // Event for the button specified by code
181  isPressed:(BOOL)isPressed // The button was pressed (YES) / released (NO)
182  fromHardwareWithAttributes:(NSMutableDictionary *)attributes; // Information on the device this event comes from
183 
184 @optional
185 
186 // Notification of ID changes
187 - (void)hidRemote:(HIDRemote *)hidRemote // Invoked when the user switched to a remote control with a different ID
188  remoteIDChangedOldID:(SInt32)old
189  newID:(SInt32)newID
190  forHardwareWithAttributes:(NSMutableDictionary *)attributes;
191 
192 // Notification about hardware additions/removals
193 - (void)hidRemote:(HIDRemote *)hidRemote // Invoked when new hardware was found / added to HIDRemote's pool
194  foundNewHardwareWithAttributes:(NSMutableDictionary *)attributes;
195 
196 - (void)hidRemote:(HIDRemote *)hidRemote // Invoked when initialization of new hardware as requested failed
197  failedNewHardwareWithError:(NSError *)error;
198 
199 - (void)hidRemote:(HIDRemote *)hidRemote // Invoked when hardware was removed from HIDRemote's pool
200  releasedHardwareWithAttributes:(NSMutableDictionary *)attributes;
201 
202 // ### WARNING: Unless you know VERY PRECISELY what you are doing, do not implement any of the delegate methods below. ###
203 
204 // Matching of newly found receiver hardware
205 - (BOOL)hidRemote:(HIDRemote *)hidRemote // Invoked when new hardware is inspected
206  inspectNewHardwareWithService:(io_service_t)service //
207  prematchResult:(BOOL)prematchResult; // Return YES if HIDRemote should go on with this hardware and try
208  // to use it, or NO if it should not be persued further.
209 
210 // Exlusive lock lending
211 - (BOOL)hidRemote:(HIDRemote *)hidRemote
212  lendExclusiveLockToApplicationWithInfo:(NSDictionary *)applicationInfo;
213 
214 - (void)hidRemote:(HIDRemote *)hidRemote
215  exclusiveLockReleasedByApplicationWithInfo:(NSDictionary *)applicationInfo;
216 
217 - (BOOL)hidRemote:(HIDRemote *)hidRemote
218  shouldRetryExclusiveLockWithInfo:(NSDictionary *)applicationInfo;
219 
220 @end
221 
222 
223 #pragma mark - Actual header file for class
224 @interface HIDRemote : NSObject
225 {
226  // IOMasterPort
227  mach_port_t _masterPort;
228 
229  // Notification ports
230  IONotificationPortRef _notifyPort;
231  CFRunLoopSourceRef _notifyRLSource;
232 
233  // Matching iterator
234  io_iterator_t _matchingServicesIterator;
235 
236  // SecureInput notification
237  io_object_t _secureInputNotification;
238 
239  // Service attributes
240  NSMutableDictionary *_serviceAttribMap;
241 
242  // Mode
243  HIDRemoteMode _mode;
244  BOOL _autoRecover;
245  NSTimer *_autoRecoveryTimer;
246 
247  // Delegate
248  NSObject <HIDRemoteDelegate> *_delegate;
249 
250  // Last seen ID and remote model
251  SInt32 _lastSeenRemoteID;
252  HIDRemoteModel _lastSeenModel;
253  SInt32 _lastSeenModelRemoteID;
254 
255  // Unused button codes
256  NSArray *_unusedButtonCodes;
257 
258  // Simulate Plus/Minus Hold
259  BOOL _simulateHoldEvents;
260 
261  // SecureEventInput workaround
262  BOOL _secureEventInputWorkAround;
263  UInt64 _lastSecureEventInputPIDSum;
264  uid_t _lastFrontUserSession;
265  BOOL _lastScreenIsLocked;
266 
267  // Exclusive lock lending
268  BOOL _exclusiveLockLending;
269  BOOL _sendExclusiveResourceReuseNotification;
270  NSNumber *_waitForReturnByPID;
271  NSNumber *_returnToPID;
272  BOOL _isRestarting;
273 
274  // Status notifications
275  BOOL _sendStatusNotifications;
276  NSString *_pidString;
277 
278  // Status
279  BOOL _applicationIsTerminating;
280  BOOL _isStopping;
281 
282  // Thread safety
283  #if HIDREMOTE_THREADSAFETY_HARDENED_NOTIFICATION_HANDLING /* #define HIDREMOTE_THREADSAFETY_HARDENED_NOTIFICATION_HANDLING if you're running your HIDRemote instance on a background thread (requires OS X 10.5 or later) */
284  NSThread *_runOnThread;
285  #endif
286 }
287 
288 #pragma mark - PUBLIC: Shared HID Remote
289 + (HIDRemote *)sharedHIDRemote;
290 
291 #pragma mark - PUBLIC: System Information
292 + (BOOL)isCandelairInstalled;
293 + (BOOL)isCandelairInstallationRequiredForRemoteMode:(HIDRemoteMode)remoteMode;
294 + (SInt32)OSXVersion;
295 - (HIDRemoteAluminumRemoteSupportLevel)aluminiumRemoteSystemSupportLevel;
296 
297 #pragma mark - PUBLIC: Interface / API
298 - (BOOL)startRemoteControl:(HIDRemoteMode)hidRemoteMode;
299 - (void)stopRemoteControl;
300 
301 - (BOOL)isStarted;
302 - (HIDRemoteMode)startedInMode;
303 
304 - (unsigned)activeRemoteControlCount;
305 
306 - (SInt32)lastSeenRemoteControlID;
307 
308 - (void)setLastSeenModel:(HIDRemoteModel)aModel;
309 - (HIDRemoteModel)lastSeenModel;
310 
311 - (void)setDelegate:(NSObject <HIDRemoteDelegate> *)newDelegate;
312 - (NSObject <HIDRemoteDelegate> *)delegate;
313 
314 - (void)setSimulateHoldEvents:(BOOL)newSimulateHoldEvents;
315 - (BOOL)simulateHoldEvents;
316 
317 - (void)setUnusedButtonCodes:(NSArray *)newArrayWithUnusedButtonCodesAsNSNumbers;
318 - (NSArray *)unusedButtonCodes;
319 
320 #pragma mark - PUBLIC: Expert APIs
321 - (void)setEnableSecureEventInputWorkaround:(BOOL)newEnableSecureEventInputWorkaround;
322 - (BOOL)enableSecureEventInputWorkaround;
323 
324 - (void)setExclusiveLockLendingEnabled:(BOOL)newExclusiveLockLendingEnabled;
325 - (BOOL)exclusiveLockLendingEnabled;
326 
327 - (BOOL)isApplicationTerminating;
328 - (BOOL)isStopping;
329 
330 #pragma mark - PRIVATE: HID Event handling
331 - (void)_handleButtonCode:(HIDRemoteButtonCode)buttonCode isPressed:(BOOL)isPressed hidAttribsDict:(NSMutableDictionary *)hidAttribsDict;
332 - (void)_sendButtonCode:(HIDRemoteButtonCode)buttonCode isPressed:(BOOL)isPressed hidAttribsDict:(NSMutableDictionary *)hidAttribsDict;
333 - (void)_hidEventFor:(io_service_t)hidDevice from:(IOHIDQueueInterface **)interface withResult:(IOReturn)result;
334 
335 #pragma mark - PRIVATE: Service setup and destruction
336 - (BOOL)_prematchService:(io_object_t)service;
337 - (HIDRemoteButtonCode)buttonCodeForUsage:(unsigned int)usage usagePage:(unsigned int)usagePage;
338 - (BOOL)_setupService:(io_object_t)service;
339 - (void)_destructService:(io_object_t)service;
340 
341 #pragma mark - PRIVATE: Distributed notifiations handling
342 - (void)_postStatusWithAction:(NSString *)action;
343 - (void)_handleNotifications:(NSNotification *)notification;
344 - (void)_setSendStatusNotifications:(BOOL)doSend;
345 - (BOOL)_sendStatusNotifications;
346 
347 #pragma mark - PRIVATE: Application becomes active / inactive handling for kHIDRemoteModeExclusiveAuto
348 - (void)_appStatusChanged:(NSNotification *)notification;
349 - (void)_delayedAutoRecovery:(NSTimer *)aTimer;
350 
351 #pragma mark - PRIVATE: Notification handling
352 - (void)_serviceMatching:(io_iterator_t)iterator;
353 - (void)_serviceNotificationFor:(io_service_t)service messageType:(natural_t)messageType messageArgument:(void *)messageArgument;
354 - (void)_updateSessionInformation;
355 - (void)_secureInputNotificationFor:(io_service_t)service messageType:(natural_t)messageType messageArgument:(void *)messageArgument;
356 
357 @end
358 
359 #pragma mark - Information attribute keys
360 extern NSString *kHIDRemoteManufacturer;
361 extern NSString *kHIDRemoteProduct;
362 extern NSString *kHIDRemoteTransport;
363 
364 #pragma mark - Internal/Expert attribute keys (AKA: don't touch these unless you really, really, REALLY know what you do)
365 extern NSString *kHIDRemoteCFPluginInterface;
366 extern NSString *kHIDRemoteHIDDeviceInterface;
367 extern NSString *kHIDRemoteCookieButtonCodeLUT;
368 extern NSString *kHIDRemoteHIDQueueInterface;
369 extern NSString *kHIDRemoteServiceNotification;
370 extern NSString *kHIDRemoteCFRunLoopSource;
371 extern NSString *kHIDRemoteLastButtonPressed;
372 extern NSString *kHIDRemoteService;
373 extern NSString *kHIDRemoteSimulateHoldEventsTimer;
374 extern NSString *kHIDRemoteSimulateHoldEventsOriginButtonCode;
375 extern NSString *kHIDRemoteAluminumRemoteSupportLevel;
376 extern NSString *kHIDRemoteAluminumRemoteSupportOnDemand;
377 
378 #pragma mark - Distributed notifications
379 extern NSString *kHIDRemoteDNHIDRemotePing;
380 extern NSString *kHIDRemoteDNHIDRemoteRetry;
381 extern NSString *kHIDRemoteDNHIDRemoteStatus;
382 
383 extern NSString *kHIDRemoteDNHIDRemoteRetryGlobalObject;
384 
385 #pragma mark - Distributed notifications userInfo keys and values
386 extern NSString *kHIDRemoteDNStatusHIDRemoteVersionKey;
387 extern NSString *kHIDRemoteDNStatusPIDKey;
388 extern NSString *kHIDRemoteDNStatusModeKey;
389 extern NSString *kHIDRemoteDNStatusUnusedButtonCodesKey;
390 extern NSString *kHIDRemoteDNStatusRemoteControlCountKey;
391 extern NSString *kHIDRemoteDNStatusReturnToPIDKey;
392 extern NSString *kHIDRemoteDNStatusActionKey;
393 extern NSString *kHIDRemoteDNStatusActionStart;
394 extern NSString *kHIDRemoteDNStatusActionStop;
395 extern NSString *kHIDRemoteDNStatusActionUpdate;
396 extern NSString *kHIDRemoteDNStatusActionNoNeed;
397 
398 #pragma mark - Driver compatibility flags
399 #ifndef HID_REMOTE_COMPATIBILITY_FLAGS_ENUM
400 #define HID_REMOTE_COMPATIBILITY_FLAGS_ENUM 1
401 typedef enum
402 {
403  kHIDRemoteCompatibilityFlagsStandardHIDRemoteDevice = 1L,
404 } HIDRemoteCompatibilityFlags;
405 #endif /* HID_REMOTE_COMPATIBILITY_FLAGS_ENUM */
Definition: HIDRemote.h:176
Definition: HIDRemote.h:224