35#import <mach/mach_error.h>
36#import <IOKit/IOKitLib.h>
37#import <IOKit/IOCFPlugIn.h>
38#import <IOKit/hid/IOHIDKeys.h>
39#import <Carbon/Carbon.h>
43- (IOHIDQueueInterface**)
queue;
45- (void) handleEventWithCookieString: (NSString*) cookieString sumOfValues: (SInt32) sumOfValues;
47- (void) remoteControlAvailable:(NSNotification *)notification;
53- (IOHIDDeviceInterface**) createInterfaceForDevice: (io_object_t) hidDevice;
65 io_object_t hidDevice = [
self findRemoteDevice];
67 IOObjectRelease(hidDevice);
74- (id) initWithDelegate: (
id) _remoteControlDelegate {
77 if ( (
self = [super initWithDelegate: _remoteControlDelegate]) ) {
83 [
self setCookieMappingInDictionary: cookieToButtonMapping];
85 NSEnumerator* enumerator = [cookieToButtonMapping objectEnumerator];
88 while( (identifier = [enumerator nextObject]) ) {
92 fixSecureEventInputBug = [[NSUserDefaults standardUserDefaults] boolForKey: @"remoteControlWrapperFixSecureEventInputBug"];
99 [
self removeNotificationObserver];
100 [
self stopListening:self];
101 [cookieToButtonMapping release];
106 [delegate sendRemoteButtonEvent: event pressedDown: pressedDown remoteControl:self];
109- (void) setCookieMappingInDictionary: (NSMutableDictionary*) cookieToButtonMap {
110 (void)cookieToButtonMap;
113- (
int) remoteIdSwitchCookie {
125- (void) setListeningToRemote: (
BOOL) value {
127 [
self stopListening:self];
129 [
self startListening:self];
136- (void) setOpenInExclusiveMode: (
BOOL) value {
143- (void) setProcessesBacklog: (
BOOL) value {
147- (void) startListening: (
id) sender {
171 [
self removeNotificationObserver];
173 io_object_t hidDevice = [[
self class] findRemoteDevice];
174 if (hidDevice == 0)
return;
176 if ([
self createInterfaceForDevice:hidDevice] == NULL) {
180 if ([
self initializeCookies]==NO) {
184 if ([
self openDevice]==NO) {
188 [
self willChangeValueForKey:@"listeningToRemote"];
189 [
self didChangeValueForKey:@"listeningToRemote"];
193 [
self stopListening:self];
194 DisableSecureEventInput();
197 IOObjectRelease(hidDevice);
200- (void) stopListening: (
id) sender {
204 BOOL sendNotification =
NO;
207 CFRunLoopRemoveSource(CFRunLoopGetCurrent(),
eventSource, kCFRunLoopDefaultMode);
212 (*queue)->stop(
queue);
215 (*queue)->dispose(
queue);
218 (*queue)->Release(
queue);
222 sendNotification =
YES;
226 [allCookies autorelease];
243 [[
self class] sendFinishedNotificationForAppIdentifier: nil];
246 [
self willChangeValueForKey:@"listeningToRemote"];
247 [
self didChangeValueForKey:@"listeningToRemote"];
254- (IOHIDQueueInterface**)
queue {
267- (NSString*) validCookieSubstring: (NSString*) cookieString {
268 if (cookieString == nil || [cookieString length] == 0)
return nil;
269 NSEnumerator* keyEnum = [[
self cookieToButtonMapping] keyEnumerator];
271 while( (key = [keyEnum nextObject]) ) {
272 NSRange range = [cookieString rangeOfString:key];
273 if (range.location == 0)
return key;
278- (void) handleEventWithCookieString: (NSString*) cookieString sumOfValues: (SInt32) sumOfValues {
285 if (cookieString == nil || [cookieString length] == 0)
return;
287 NSNumber* buttonId = [[
self cookieToButtonMapping] objectForKey: cookieString];
288 if (buttonId != nil) {
289 switch ( [buttonId intValue] )
293 buttonId = [NSNumber numberWithInt:kRemoteButtonPlay];
298 [
self sendRemoteButtonEvent: [buttonId intValue] pressedDown: (sumOfValues>0)];
303 NSString* subCookieString;
304 NSString* lastSubCookieString=nil;
305 while( (subCookieString = [
self validCookieSubstring: cookieString]) ) {
306 cookieString = [cookieString substringFromIndex: [subCookieString length]];
307 lastSubCookieString = subCookieString;
308 if (processesBacklog) [
self handleEventWithCookieString: subCookieString sumOfValues:sumOfValues];
310 if (processesBacklog == NO && lastSubCookieString != nil) {
315 [
self handleEventWithCookieString: lastSubCookieString sumOfValues:0];
317 if ([cookieString length] > 0) {
318 NSLog(
@"Apple Remote: Unknown button for cookiestring %@", cookieString);
324 [[NSDistributedNotificationCenter defaultCenter] removeObserver:self name:FINISHED_USING_REMOTE_CONTROL_NOTIFICATION object:nil];
327- (void) remoteControlAvailable:(NSNotification *)notification {
329 [
self removeNotificationObserver];
330 [
self startListening: self];
341 if ((intptr_t)target < 0) {
342 NSLog(
@"Apple Remote: QueueCallbackFunction called with invalid target!");
345 NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
348 IOHIDEventStruct event;
349 AbsoluteTime
const zeroTime = {0,0};
350 NSMutableString* cookieString = [NSMutableString string];
351 SInt32 sumOfValues = 0;
352 while (
result == kIOReturnSuccess)
354 result = (*[remote
queue])->getNextEvent([remote
queue], &event, zeroTime, 0);
355 if (
result != kIOReturnSuccess )
360 if (((
int)
event.elementCookie)!=5) {
361 sumOfValues+=
event.value;
362 [cookieString appendString:[NSString stringWithFormat:@"%lld_", (long long) (intptr_t) event.elementCookie]];
365 [remote handleEventWithCookieString: cookieString sumOfValues: sumOfValues];
372- (IOHIDDeviceInterface**) createInterfaceForDevice: (io_object_t) hidDevice {
374 IOCFPlugInInterface** plugInInterface =
NULL;
375 HRESULT plugInResult = S_OK;
377 IOReturn ioReturnValue = kIOReturnSuccess;
381 ioReturnValue = IOObjectGetClass(hidDevice, className);
383 if (ioReturnValue != kIOReturnSuccess) {
384 NSLog(
@"Apple Remote: Error: Failed to get RemoteControlDevice class name.");
388 ioReturnValue = IOCreatePlugInInterfaceForService(hidDevice,
389 kIOHIDDeviceUserClientTypeID,
390 kIOCFPlugInInterfaceID,
393 if (ioReturnValue == kIOReturnSuccess)
396 plugInResult = (*plugInInterface)->QueryInterface(plugInInterface, CFUUIDGetUUIDBytes(kIOHIDDeviceInterfaceID), (LPVOID) &
hidDeviceInterface);
398 if (plugInResult != S_OK) {
399 NSLog(
@"Apple Remote: Error: Couldn't create HID class device interface");
402 if (plugInInterface) (*plugInInterface)->Release(plugInInterface);
409 IOHIDElementCookie cookie;
411 NSArray* elements = nil;
412 NSDictionary* element;
415 if (!handle || !(*handle))
return NO;
421 success = (*handle)->copyMatchingElements(handle, NULL, (CFArrayRef*)&elements);
423 if (success == kIOReturnSuccess) {
429 allCookies = [[NSMutableArray alloc] init];
431 NSEnumerator *elementsEnumerator = [elements objectEnumerator];
433 while ( (element = [elementsEnumerator nextObject]) ) {
435 object = [element valueForKey: (NSString*)CFSTR(kIOHIDElementCookieKey) ];
436 if (
object == nil || ![
object isKindOfClass:[NSNumber
class]])
continue;
437 if (
object == NULL || CFGetTypeID(
object) != CFNumberGetTypeID())
continue;
438 cookie = (IOHIDElementCookie) [
object longValue];
440 [allCookies addObject: [NSNumber numberWithInt:(int)cookie]];
452 IOHIDOptionsType openMode = kIOHIDOptionsTypeNone;
453 if ([
self isOpenInExclusiveMode]) openMode = kIOHIDOptionsTypeSeizeDevice;
456 if (ioReturnValue == KERN_SUCCESS) {
459 (*queue)->create(
queue, 0, 12);
461 IOHIDElementCookie cookie;
462 NSEnumerator *allCookiesEnumerator = [allCookies objectEnumerator];
464 while ( (cookie = (IOHIDElementCookie)[[allCookiesEnumerator nextObject] intValue]) ) {
465 (*queue)->addElement(
queue, cookie, 0);
469 ioReturnValue = (*queue)->createAsyncEventSource(
queue, &eventSource);
470 if (ioReturnValue == KERN_SUCCESS) {
472 if (ioReturnValue == KERN_SUCCESS) {
473 CFRunLoopAddSource(CFRunLoopGetCurrent(), eventSource, kCFRunLoopDefaultMode);
476 (*queue)->start(
queue);
479 NSLog(
@"Apple Remote: Error when setting event callback");
482 NSLog(
@"Apple Remote: Error when creating async event source");
485 NSLog(
@"Apple Remote: Error when opening device");
487 }
else if (ioReturnValue == kIOReturnExclusiveAccess) {
491 [[NSDistributedNotificationCenter defaultCenter] addObserver:self selector:@selector(remoteControlAvailable:) name:FINISHED_USING_REMOTE_CONTROL_NOTIFICATION object:nil];
494 [[
self class] sendRequestForRemoteControlNotification];
500 CFMutableDictionaryRef hidMatchDictionary =
NULL;
501 IOReturn ioReturnValue = kIOReturnSuccess;
502 io_iterator_t hidObjectIterator = 0;
503 io_object_t hidDevice = 0;
507 hidMatchDictionary = IOServiceMatching([
self remoteControlDeviceName]);
511 ioReturnValue = IOServiceGetMatchingServices(kIOMasterPortDefault, hidMatchDictionary, &hidObjectIterator);
514 if ((ioReturnValue == kIOReturnSuccess) && (hidObjectIterator != 0)) {
515 hidDevice = IOIteratorNext(hidObjectIterator);
519 IOObjectRelease(hidObjectIterator);
static void QueueCallbackFunction(void *target, IOReturn result, void *refcon, void *sender)
RemoteControlEventIdentifier
@ kMetallicRemote2009ButtonMiddlePlay
@ kMetallicRemote2009ButtonPlay
io_object_t findRemoteDevice()
IOHIDDeviceInterface ** hidDeviceInterface()
NSDictionary * cookieToButtonMapping()
void removeNotificationObserver()
IOHIDQueueInterface ** queue()
BOOL isListeningToRemote()
BOOL isOpenInExclusiveMode()
const char * remoteControlDeviceName()
NSMutableArray * allCookies
IOHIDQueueInterface ** queue
CFRunLoopSourceRef eventSource
BOOL fixSecureEventInputBug
int supportedButtonEvents
tDoubleVectorPair cleanup(const css::uno::Sequence< double > &rXValues, const css::uno::Sequence< double > &rYValues, Pred aPred)
const wchar_t *typedef BOOL
const wchar_t *typedef int(__stdcall *DllNativeUnregProc)(int
::boost::spirit::classic::rule< ScannerT > identifier
#define SAL_WNODEPRECATED_DECLARATIONS_POP
#define SAL_WNODEPRECATED_DECLARATIONS_PUSH