📄 appleremote.m
字号:
if (simulatePlusMinusHold) { if (event == kRemoteButtonVolume_Plus || event == kRemoteButtonVolume_Minus) { if (pressedDown) { lastPlusMinusEvent = event; lastPlusMinusEventTime = [NSDate timeIntervalSinceReferenceDate]; [self performSelector:@selector(sendSimulatedPlusMinusEvent:) withObject:[NSNumber numberWithDouble:lastPlusMinusEventTime] afterDelay:HOLD_RECOGNITION_TIME_INTERVAL]; return; } else { if (lastEventSimulatedHold) { event = (event==kRemoteButtonVolume_Plus) ? kRemoteButtonVolume_Plus_Hold : kRemoteButtonVolume_Minus_Hold; lastPlusMinusEvent = 0; lastEventSimulatedHold = NO; } else { @synchronized(self) { lastPlusMinusEvent = 0; } pressedDown = YES; } } } } if (([self clickCountEnabledButtons] & event) == event) { if (pressedDown==NO && (event == kRemoteButtonVolume_Minus || event == kRemoteButtonVolume_Plus)) { return; // this one is triggered automatically by the handler } NSNumber* eventNumber; NSNumber* timeNumber; @synchronized(self) { lastClickCountEventTime = [NSDate timeIntervalSinceReferenceDate]; if (lastClickCountEvent == event) { eventClickCount = eventClickCount + 1; } else { eventClickCount = 1; } lastClickCountEvent = event; timeNumber = [NSNumber numberWithDouble:lastClickCountEventTime]; eventNumber= [NSNumber numberWithUnsignedInt:event]; } [self performSelector: @selector(executeClickCountEvent:) withObject: [NSArray arrayWithObjects:eventNumber, timeNumber, nil] afterDelay: maxClickTimeDifference]; } else { [delegate appleRemoteButton:event pressedDown: pressedDown clickCount:1]; } }}- (void) executeClickCountEvent: (NSArray*) values { AppleRemoteEventIdentifier event = [[values objectAtIndex: 0] unsignedIntValue]; NSTimeInterval eventTimePoint = [[values objectAtIndex: 1] doubleValue]; BOOL finishedClicking = NO; int finalClickCount = eventClickCount; @synchronized(self) { finishedClicking = (event != lastClickCountEvent || eventTimePoint == lastClickCountEventTime); if (finishedClicking) eventClickCount = 0; } if (finishedClicking) { [delegate appleRemoteButton:event pressedDown: YES clickCount:finalClickCount]; if ([self simulatesPlusMinusHold]==NO && (event == kRemoteButtonVolume_Minus || event == kRemoteButtonVolume_Plus)) { // trigger a button release event, too [NSThread sleepUntilDate: [NSDate dateWithTimeIntervalSinceNow:0.1]]; [delegate appleRemoteButton:event pressedDown: NO clickCount:finalClickCount]; } }}- (void) handleEventWithCookieString: (NSString*) cookieString sumOfValues: (SInt32) sumOfValues { /* if (previousRemainingCookieString) { cookieString = [previousRemainingCookieString stringByAppendingString: cookieString]; NSLog(@"New cookie string is %@", cookieString); [previousRemainingCookieString release], previousRemainingCookieString=nil; }*/ if (cookieString == nil || [cookieString length] == 0) return; NSNumber* buttonId = [[self cookieToButtonMapping] objectForKey: cookieString]; if (buttonId != nil) { [self sendRemoteButtonEvent: [buttonId intValue] pressedDown: (sumOfValues>0)]; } else { // let's see if a number of events are stored in the cookie string. this does // happen when the main thread is too busy to handle all incoming events in time. NSString* subCookieString; NSString* lastSubCookieString=nil; while(subCookieString = [self validCookieSubstring: cookieString]) { cookieString = [cookieString substringFromIndex: [subCookieString length]]; lastSubCookieString = subCookieString; if (processesBacklog) [self handleEventWithCookieString: subCookieString sumOfValues:sumOfValues]; } if (processesBacklog == NO && lastSubCookieString != nil) { // process the last event of the backlog and assume that the button is not pressed down any longer. // The events in the backlog do not seem to be in order and therefore (in rare cases) the last event might be // a button pressed down event while in reality the user has released it. // NSLog(@"processing last event of backlog"); [self handleEventWithCookieString: lastSubCookieString sumOfValues:0]; } if ([cookieString length] > 0) { NSLog(@"Unknown button for cookiestring %@", cookieString); } }}@end/* Callback method for the device queueWill be called for any event of any type (cookie) to which we subscribe*/static void QueueCallbackFunction(void* target, IOReturn result, void* refcon, void* sender) { AppleRemote* remote = (AppleRemote*)target; IOHIDEventStruct event; AbsoluteTime zeroTime = {0,0}; NSMutableString* cookieString = [NSMutableString string]; SInt32 sumOfValues = 0; 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_SWITCH_COOKIE == (int)event.elementCookie) { [remote setRemoteId: event.value]; [remote handleEventWithCookieString: @"19_" sumOfValues: 0]; } else { if (((int)event.elementCookie)!=5) { sumOfValues+=event.value; [cookieString appendString:[NSString stringWithFormat:@"%d_", event.elementCookie]]; } } } [remote handleEventWithCookieString: cookieString sumOfValues: sumOfValues];}@implementation AppleRemote (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;}- (io_object_t) findAppleRemoteDevice { 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(AppleRemoteDeviceName); // 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;}- (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]; int i; for (i=0; i< [elements count]; i++) { element = [elements objectAtIndex:i]; //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. int i=0; for(i=0; i<[allCookies count]; i++) { IOHIDElementCookie cookie = (IOHIDElementCookie)[[allCookies objectAtIndex:i] intValue]; (*queue)->addElement(queue, cookie, 0); } // add callback for async events CFRunLoopSourceRef eventSource; 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 callout"); } } else { NSLog(@"Error when creating async event source"); } } else { NSLog(@"Error when opening device"); } } return NO;}@end@implementation AppleRemoteApplicationDelegate- (id) initWithApplicationDelegate: (id) delegate { if (self = [super init]) { applicationDelegate = [delegate retain]; } return self;}- (void) dealloc { NSLog(@"Dealloc"); [applicationDelegate release]; [super dealloc];}- (id) applicationDelegate { return applicationDelegate;}- (void)applicationWillBecomeActive:(NSNotification *)aNotification { if ([applicationDelegate respondsToSelector: @selector(applicationWillBecomeActive:)]) { [applicationDelegate applicationWillBecomeActive: aNotification]; }}- (void)applicationDidBecomeActive:(NSNotification *)aNotification { [[AppleRemote sharedRemote] setListeningToRemote: YES]; if ([applicationDelegate respondsToSelector: @selector(applicationDidBecomeActive:)]) { [applicationDelegate applicationDidBecomeActive: aNotification]; }}- (void)applicationWillResignActive:(NSNotification *)aNotification { [[AppleRemote sharedRemote] setListeningToRemote: NO]; if ([applicationDelegate respondsToSelector: @selector(applicationWillResignActive:)]) { [applicationDelegate applicationWillResignActive: aNotification]; }}- (void)applicationDidResignActive:(NSNotification *)aNotification { if ([applicationDelegate respondsToSelector: @selector(applicationDidResignActive:)]) { [applicationDelegate applicationDidResignActive: aNotification]; }}- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector { NSMethodSignature* signature = [super methodSignatureForSelector: aSelector]; if (signature == nil && applicationDelegate != nil) { signature = [applicationDelegate methodSignatureForSelector: aSelector]; } return signature;}- (void)forwardInvocation:(NSInvocation *)invocation { SEL aSelector = [invocation selector]; if (applicationDelegate==nil || [applicationDelegate respondsToSelector:aSelector]==NO) { [super forwardInvocation: invocation]; return; } [invocation invokeWithTarget:applicationDelegate];}@end
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -