| // |
| // GTMCarbonEvent.m |
| // |
| // Copyright 2006-2008 Google Inc. |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); you may not |
| // use this file except in compliance with the License. You may obtain a copy |
| // of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT |
| // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the |
| // License for the specific language governing permissions and limitations under |
| // the License. |
| // |
| |
| #import "GTMCarbonEvent.h" |
| #import <AppKit/AppKit.h> |
| #import "GTMDebugSelectorValidation.h" |
| #import "GTMTypeCasting.h" |
| |
| // Wrapper for all the info we need about a hotkey that we can store in a |
| // Foundation storage class. |
| @interface GTMCarbonHotKey (GTMCarbonHotKeyPrivate) |
| |
| // Create a HotKey record |
| // Arguments: |
| // keyID - id of the hotkey |
| // target - object we are going to call when the hotkey is hit |
| // action - selector we are going to call on target |
| // userInfo - user storage |
| // whenPressed - do we do it on key down or key up? |
| // Returns: |
| // a hotkey record, or nil on failure |
| - (id)initWithHotKey:(EventHotKeyID)keyID |
| target:(id)target |
| action:(SEL)selector |
| userInfo:(id)userInfo |
| whenPressed:(BOOL)onKeyDown; |
| |
| // Does this record match key |keyID| |
| // Arguments: |
| // keyID - the id to match against |
| // Returns: |
| // Yes if we match this key id |
| - (BOOL)matchesHotKeyID:(EventHotKeyID)keyID; |
| |
| // Make target perform selector |
| // Returns: |
| // Yes if handled |
| - (BOOL)sendAction; |
| |
| - (void)setHotKeyRef:(EventHotKeyRef)ref; |
| @end |
| |
| @implementation GTMCarbonEvent |
| |
| // Create an event of class |inClass| and kind |inKind| |
| // |
| // Returns: |
| // Autoreleased GTMCarbonEvent |
| // |
| + (id)eventWithClass:(UInt32)inClass kind:(UInt32)kind { |
| return [[[self alloc] initWithClass:inClass kind:kind] autorelease]; |
| } |
| |
| |
| // Create an event based on |event|. Retains |event|. |
| // |
| // Returns: |
| // Autoreleased GTMCarbonEvent |
| // |
| + (id)eventWithEvent:(EventRef)event { |
| return [[[self alloc] initWithEvent:event] autorelease]; |
| } |
| |
| |
| // Create an event based on the event currently being handled. |
| // |
| // Returns: |
| // Autoreleased GTMCarbonEvent |
| // |
| + (id)currentEvent { |
| return [self eventWithEvent:GetCurrentEvent()]; |
| } |
| |
| |
| // Create an event of class |inClass| and kind |inKind| |
| // |
| // Returns: |
| // GTMCarbonEvent |
| // |
| - (id)initWithClass:(UInt32)inClass kind:(UInt32)kind { |
| if ((self = [super init])) { |
| verify_noerr(CreateEvent(kCFAllocatorDefault, inClass, kind, |
| 0, kEventAttributeNone, &event_)); |
| } |
| return self; |
| } |
| |
| |
| // Create an event based on |event|. Retains |event|. |
| // |
| // Returns: |
| // GTMCarbonEvent |
| // |
| - (id)initWithEvent:(EventRef)event { |
| if ((self = [super init])) { |
| if (event) { |
| event_ = RetainEvent(event); |
| } |
| } |
| return self; |
| } |
| |
| |
| // This does a proper event copy, but ignores the |zone|. No way to do a copy |
| // of an event into a specific zone. |
| // |
| // Arguments: |
| // zone - the zone to copy to |
| // Returns: |
| // the copied event. nil on failure |
| - (id)copyWithZone:(NSZone *)zone { |
| GTMCarbonEvent *carbonEvent = nil; |
| EventRef newEvent = CopyEvent([self event]); |
| if (newEvent) { |
| carbonEvent = [[[self class] allocWithZone:zone] initWithEvent:newEvent]; |
| ReleaseEvent(newEvent); |
| } |
| return carbonEvent; |
| } |
| |
| // releases our retained event |
| // |
| - (void)dealloc { |
| if (event_) { |
| ReleaseEvent(event_); |
| event_ = NULL; |
| } |
| [super dealloc]; |
| } |
| |
| // description utliity for debugging |
| // |
| - (NSString *)description { |
| // Use 8 bytes because stack protection gives us a warning if we use a |
| // smaller buffer. |
| char cls[8]; |
| UInt32 kind; |
| |
| // Need everything bigendian if we are printing out the class as a "string" |
| *((UInt32 *)cls) = CFSwapInt32HostToBig([self eventClass]); |
| kind = [self eventKind]; |
| cls[4] = 0; |
| return [NSString stringWithFormat:@"GTMCarbonEvent '%s' %lu", |
| cls, (unsigned long)kind]; |
| } |
| |
| |
| // Get the event's class. |
| // |
| // Returns: |
| // event class |
| // |
| - (UInt32)eventClass { |
| return GetEventClass(event_); |
| } |
| |
| |
| // Get the event's kind. |
| // |
| // Returns: |
| // event kind |
| // |
| - (UInt32)eventKind { |
| return GetEventKind(event_); |
| } |
| |
| |
| // Set the event's time. |
| // |
| // Arguments: |
| // time - the time you want associated with the event |
| // |
| - (void)setTime:(EventTime)eventTime { |
| verify_noerr(SetEventTime(event_, eventTime)); |
| } |
| |
| |
| // Get the event's time. |
| // |
| // Returns: |
| // the time associated with the event |
| // |
| - (EventTime)time { |
| return GetEventTime(event_); |
| } |
| |
| |
| // Get the event's eventref for passing to other carbon functions. |
| // |
| // Returns: |
| // the event ref associated with the event |
| // |
| - (EventRef)event { |
| return event_; |
| } |
| |
| |
| // Sends event to an event target with options |
| // |
| // Arguments: |
| // target - target to send event to. |
| // options - options to send event. See SendEventToEventTargetWithOptions |
| // for details. |
| // |
| // Returns: |
| // OSStatus value. |
| // |
| - (OSStatus)sendToTarget:(GTMCarbonEventHandler *)target |
| options:(OptionBits)options { |
| return SendEventToEventTargetWithOptions(event_, |
| [target eventTarget], options); |
| } |
| |
| // Post event to an event queue. |
| // |
| // Arguments: |
| // queue - queue to post it to. |
| // priority - priority to post it with |
| // |
| // Returns: |
| // OSStatus value. |
| // |
| - (OSStatus)postToQueue:(EventQueueRef)queue priority:(EventPriority)priority { |
| return PostEventToQueue(queue, event_, priority); |
| } |
| |
| |
| // Post event to current queue with standard priority. |
| // |
| - (void)postToCurrentQueue { |
| verify_noerr([self postToQueue:GetCurrentEventQueue() |
| priority:kEventPriorityStandard]); |
| } |
| |
| |
| // Post event to main queue with standard priority. |
| // |
| - (void)postToMainQueue { |
| verify_noerr([self postToQueue:GetMainEventQueue() |
| priority:kEventPriorityStandard]); |
| } |
| |
| |
| // Sets (or adds) a parameter to an event. Try not to use this function |
| // directly. Look at the PARAM_TEMPLATE_DECL/DEFN macros below. |
| // |
| // Arguments: |
| // name - the parameter name. |
| // type - the parameter type. |
| // size - the size of the data that |data| points to. |
| // data - pointer to the data you want to set the parameter to. |
| // |
| - (void)setParameterNamed:(EventParamName)name |
| type:(EventParamType)type |
| size:(ByteCount)size |
| data:(const void *)data { |
| verify_noerr(SetEventParameter(event_, name, type, size, data)); |
| } |
| |
| |
| // Gets a parameter from an event. Try not to use this function |
| // directly. Look at the PARAM_TEMPLATE_DECL/DEFN macros below. |
| // |
| // Arguments: |
| // name - the parameter name. |
| // type - the parameter type. |
| // size - the size of the data that |data| points to. |
| // data - pointer to the buffer that you want to fill with your data. |
| // |
| // Returns: |
| // YES is parameter is retrieved successfully. NO if parameter doesn't exist. |
| // |
| - (BOOL)getParameterNamed:(EventParamName)name |
| type:(EventParamType)type |
| size:(ByteCount)size |
| data:(void *)data { |
| OSStatus status = GetEventParameter(event_, name, type, |
| NULL, size, NULL, data); |
| return status == noErr; |
| } |
| |
| |
| // Gets a the size of a parameter from an event. |
| // |
| // Arguments: |
| // name - the parameter name. |
| // type - the parameter type. |
| // |
| // Returns: |
| // The size of the buffer required to hold the parameter. 0 if parameter |
| // doesn't exist. |
| // |
| - (ByteCount)sizeOfParameterNamed:(EventParamName)name |
| type:(EventParamType)type { |
| ByteCount size = 0; |
| verify_noerr(GetEventParameter(event_, name, type, NULL, 0, &size, NULL)); |
| return size; |
| } |
| |
| @end |
| |
| @implementation GTMCarbonEvent (GTMCarbonEventGettersAndSetters) |
| GTM_PARAM_TEMPLATE_DEFN(UInt32) |
| GTM_PARAM_TEMPLATE_DEFN(EventHotKeyID) |
| @end |
| |
| UInt32 GTMCocoaToCarbonKeyModifiers(NSUInteger inCocoaModifiers) { |
| UInt32 carbModifiers = 0; |
| if (inCocoaModifiers & NSAlphaShiftKeyMask) carbModifiers |= alphaLock; |
| if (inCocoaModifiers & NSShiftKeyMask) carbModifiers |= shiftKey; |
| if (inCocoaModifiers & NSControlKeyMask) carbModifiers |= controlKey; |
| if (inCocoaModifiers & NSAlternateKeyMask) carbModifiers |= optionKey; |
| if (inCocoaModifiers & NSCommandKeyMask) carbModifiers |= cmdKey; |
| return carbModifiers; |
| } |
| |
| NSUInteger GTMCarbonToCocoaKeyModifiers(UInt32 inCarbonModifiers) { |
| NSUInteger nsModifiers = 0; |
| if (inCarbonModifiers & alphaLock) nsModifiers |= NSAlphaShiftKeyMask; |
| if (inCarbonModifiers & shiftKey) nsModifiers |= NSShiftKeyMask; |
| if (inCarbonModifiers & controlKey) nsModifiers |= NSControlKeyMask; |
| if (inCarbonModifiers & optionKey) nsModifiers |= NSAlternateKeyMask; |
| if (inCarbonModifiers & cmdKey) nsModifiers |= NSCommandKeyMask; |
| return nsModifiers; |
| } |
| |
| const OSType kGTMCarbonFrameworkSignature = 'GTM '; |
| |
| @implementation GTMCarbonEventHandler |
| |
| -(void)dealloc { |
| if (eventHandler_) { |
| verify_noerr(RemoveEventHandler(eventHandler_)); |
| } |
| [super dealloc]; |
| } |
| // Does our delegate respond to eventHandler:receivedEvent:handler: |
| // |
| // Returns: |
| // YES if delegate responds to eventHandler:receivedEvent:handler: |
| - (BOOL) delegateRespondsToHandleEvent { |
| return delegateRespondsToHandleEvent_; |
| } |
| |
| // Registers the event handler to listen for |events|. |
| // |
| // Arguments: |
| // events - an array of EventTypeSpec. The events to register for. |
| // count - the number of EventTypeSpecs in events. |
| // |
| - (void)registerForEvents:(const EventTypeSpec *)events count:(size_t)count { |
| verify_noerr(AddEventTypesToHandler([self eventHandler], count, events)); |
| } |
| |
| // Causes the event handler to stop listening for |events|. |
| // |
| // Arguments: |
| // events - an array of EventTypeSpec. The events to register for. |
| // count - the number of EventTypeSpecs in events. |
| // |
| - (void)unregisterForEvents:(const EventTypeSpec *)events count:(size_t)count { |
| verify_noerr(RemoveEventTypesFromHandler([self eventHandler], count, events)); |
| } |
| |
| // To be overridden by subclasses to respond to events. All subclasses should |
| // call [super handleEvent:handler:] if they don't handle the event themselves. |
| // |
| // Arguments: |
| // event - the event to be handled |
| // handler - the call ref in case you want to call CallNextEventHandler |
| // in your method |
| // Returns: |
| // OSStatus - usually either noErr or eventNotHandledErr |
| // |
| - (OSStatus)handleEvent:(GTMCarbonEvent *)event |
| handler:(EventHandlerCallRef)handler { |
| OSStatus status = eventNotHandledErr; |
| require(event, CantUseParams); |
| require(handler, CantUseParams); |
| require([event event], CantUseParams); |
| status = CallNextEventHandler(handler, [event event]); |
| CantUseParams: |
| return status; |
| } |
| |
| // To be overridden by subclasses to return the event target for the class. |
| // GTMCarbonEventHandler's implementation returns NULL. |
| // |
| // Returns: |
| // The event target ref. |
| // |
| - (EventTargetRef)eventTarget { |
| // Defaults implementation needs to be overridden |
| return NULL; |
| } |
| |
| // C callback for our registered EventHandlerUPP. |
| // |
| // Arguments: |
| // inHandler - handler given to us from Carbon Event system |
| // inEvent - the event we are handling |
| // inUserData - refcon that we gave to the carbon event system. Is a |
| // GTMCarbonEventHandler in disguise. |
| // Returns: |
| // status of event handler |
| // |
| static OSStatus EventHandler(EventHandlerCallRef inHandler, |
| EventRef inEvent, |
| void *inUserData) { |
| GTMCarbonEvent *event = [GTMCarbonEvent eventWithEvent:inEvent]; |
| GTMCarbonEventHandler *handler |
| = GTM_STATIC_CAST(GTMCarbonEventHandler, inUserData); |
| |
| // First check to see if our delegate cares about this event. If the delegate |
| // handles it (i.e responds to it and does not return eventNotHandledErr) we |
| // do not pass it on to default handling. |
| OSStatus status = eventNotHandledErr; |
| if ([handler delegateRespondsToHandleEvent]) { |
| status = [[handler delegate] gtm_eventHandler:handler |
| receivedEvent:event |
| handler:inHandler]; |
| } |
| if (status == eventNotHandledErr) { |
| status = [handler handleEvent:event handler:inHandler]; |
| } |
| return status; |
| } |
| |
| // Gets the underlying EventHandlerRef for that this class wraps. |
| // |
| // Returns: |
| // The EventHandlerRef this class wraps. |
| // |
| - (EventHandlerRef)eventHandler { |
| if (!eventHandler_) { |
| static EventHandlerUPP sHandlerProc = NULL; |
| if ( sHandlerProc == NULL ) { |
| sHandlerProc = NewEventHandlerUPP(EventHandler); |
| } |
| verify_noerr(InstallEventHandler([self eventTarget], |
| sHandlerProc, 0, |
| NULL, self, &eventHandler_)); |
| } |
| return eventHandler_; |
| } |
| |
| // Gets the delegate for the handler |
| // |
| // Returns: |
| // the delegate |
| - (id)delegate { |
| return delegate_; |
| } |
| |
| // Sets the delegate for the handler and caches whether it responds to |
| // the eventHandler:receivedEvent:handler: selector for performance purposes. |
| // |
| // Arguments: |
| // delegate - the delegate for the handler |
| - (void)setDelegate:(id)delegate { |
| delegate_ = delegate; |
| SEL selector = @selector(gtm_eventHandler:receivedEvent:handler:); |
| delegateRespondsToHandleEvent_ = [delegate respondsToSelector:selector]; |
| } |
| |
| @end |
| |
| @implementation GTMCarbonEventMonitorHandler |
| |
| + (GTMCarbonEventMonitorHandler *)sharedEventMonitorHandler { |
| static GTMCarbonEventMonitorHandler *obj = nil; |
| if (!obj) { |
| obj = [[self alloc] init]; |
| } |
| return obj; |
| } |
| |
| - (EventTargetRef)eventTarget { |
| return GetEventMonitorTarget(); |
| } |
| |
| @end |
| |
| #if (MAC_OS_X_VERSION_MAX_ALLOWED == MAC_OS_X_VERSION_10_5) |
| // Accidentally marked as !LP64 in the 10.5sdk, it's back in the 10.6 sdk. |
| // If you remove this decl, please remove it from GTMCarbonEventTest.m as well. |
| extern EventTargetRef GetApplicationEventTarget(void); |
| #endif // (MAC_OS_X_VERSION_MAX_ALLOWED == MAC_OS_X_VERSION_10_5) |
| |
| @implementation GTMCarbonEventApplicationEventHandler |
| |
| + (GTMCarbonEventApplicationEventHandler *)sharedApplicationEventHandler { |
| static GTMCarbonEventApplicationEventHandler *obj = nil; |
| if (!obj) { |
| obj = [[self alloc] init]; |
| } |
| return obj; |
| } |
| |
| - (EventTargetRef)eventTarget { |
| return GetApplicationEventTarget(); |
| } |
| |
| @end |
| |
| @implementation GTMCarbonEventDispatcherHandler |
| |
| + (GTMCarbonEventDispatcherHandler *)sharedEventDispatcherHandler { |
| static GTMCarbonEventDispatcherHandler *obj = nil; |
| if (!obj) { |
| obj = [[self alloc] init]; |
| } |
| return obj; |
| } |
| |
| // Register for the events we handle, and set up the dictionaries we need |
| // to keep track of the hotkeys and commands that we handle. |
| // Returns: |
| // GTMCarbonApplication or nil on failure |
| - (id)init { |
| if ((self = [super init])) { |
| static EventTypeSpec events[] = { |
| { kEventClassKeyboard, kEventHotKeyPressed }, |
| { kEventClassKeyboard, kEventHotKeyReleased }, |
| }; |
| [self registerForEvents:events count:GetEventTypeCount(events)]; |
| hotkeys_ = [[NSMutableArray alloc] initWithCapacity:0]; |
| } |
| return self; |
| } |
| |
| // COV_NF_START |
| // Singleton, we never get released. Just here for completeness. |
| - (void)dealloc { |
| [hotkeys_ release]; |
| [super dealloc]; |
| } |
| // COV_NF_END |
| |
| - (EventTargetRef)eventTarget { |
| return GetEventDispatcherTarget(); |
| } |
| |
| // Registers a hotkey. When the hotkey is executed by the user, target will be |
| // called with selector. |
| // Arguments: |
| // keyCode - the virtual keycode of the hotkey |
| // cocoaModifiers - the modifiers that need to be used with |keyCode|. NB |
| // that these are cocoa modifiers, so NSCommandKeyMask etc. |
| // target - instance that will get |action| called when the hotkey fires |
| // action - the method to call on |target| when the hotkey fires |
| // action should have the signature - (void)handler:(GTMCarbonEventDispatcherHandler *)handler |
| // userInfo - user storage |
| // onKeyDown - is YES, the hotkey fires on the keydown (usual) otherwise |
| // it fires on the key up. |
| // Returns: |
| // a EventHotKeyRef that you can use with other Carbon functions, or for |
| // unregistering the hotkey. Note that all hotkeys are unregistered |
| // automatically when an app quits. Will be NULL on failure. |
| - (GTMCarbonHotKey *)registerHotKey:(NSUInteger)keyCode |
| modifiers:(NSUInteger)cocoaModifiers |
| target:(id)target |
| action:(SEL)selector |
| userInfo:(id)userInfo |
| whenPressed:(BOOL)onKeyDown { |
| static UInt32 sCurrentID = 0; |
| |
| GTMCarbonHotKey *newKey = nil; |
| EventHotKeyRef theRef = NULL; |
| EventHotKeyID keyID; |
| keyID.signature = kGTMCarbonFrameworkSignature; |
| keyID.id = ++sCurrentID; |
| newKey = [[[GTMCarbonHotKey alloc] initWithHotKey:keyID |
| target:target |
| action:selector |
| userInfo:userInfo |
| whenPressed:onKeyDown] autorelease]; |
| require(newKey, CantCreateKey); |
| require_noerr_action(RegisterEventHotKey((UInt32)keyCode, |
| GTMCocoaToCarbonKeyModifiers(cocoaModifiers), |
| keyID, |
| [self eventTarget], |
| 0, |
| &theRef), |
| CantRegisterHotKey, newKey = nil); |
| [newKey setHotKeyRef:theRef]; |
| [hotkeys_ addObject:newKey]; |
| |
| CantRegisterHotKey: |
| CantCreateKey: |
| return newKey; |
| } |
| |
| // Unregisters a hotkey previously registered with registerHotKey. |
| // Arguments: |
| // keyRef - the EventHotKeyRef to unregister |
| - (void)unregisterHotKey:(GTMCarbonHotKey *)keyRef { |
| check([hotkeys_ containsObject:keyRef]); |
| [[keyRef retain] autorelease]; |
| [hotkeys_ removeObject:keyRef]; |
| verify_noerr(UnregisterEventHotKey([keyRef hotKeyRef])); |
| } |
| |
| // A hotkey has been hit. See if it is one of ours, and if so fire it. |
| // Arguments: |
| // event - the hotkey even that was received |
| // Returns: |
| // Yes if handled. |
| - (BOOL)handleHotKeyEvent:(GTMCarbonEvent *)event { |
| EventHotKeyID keyID; |
| BOOL handled = [event getEventHotKeyIDParameterNamed:kEventParamDirectObject |
| data:&keyID]; |
| if (handled) { |
| GTMCarbonHotKey *hotkey; |
| for (hotkey in hotkeys_) { |
| if ([hotkey matchesHotKeyID:keyID]) { |
| EventKind kind = [event eventKind]; |
| BOOL onKeyDown = [hotkey onKeyDown]; |
| if ((kind == kEventHotKeyPressed && onKeyDown) || |
| (kind == kEventHotKeyReleased && !onKeyDown)) { |
| handled = [hotkey sendAction]; |
| } |
| break; |
| } |
| } |
| } |
| return handled; |
| } |
| |
| // Currently we handle hotkey and command events here. If we get one of them |
| // we dispatch them off to the handlers above. Otherwise we just call up to |
| // super. |
| // Arguments: |
| // event - the event to check |
| // handler - the handler call ref |
| // Returns: |
| // OSStatus |
| - (OSStatus)handleEvent:(GTMCarbonEvent *)event |
| handler:(EventHandlerCallRef)handler { |
| OSStatus theStatus = eventNotHandledErr; |
| if ([event eventClass] == kEventClassKeyboard) { |
| EventKind kind = [event eventKind]; |
| if (kind == kEventHotKeyPressed || kind == kEventHotKeyReleased) { |
| theStatus = [self handleHotKeyEvent:event] ? noErr : eventNotHandledErr; |
| } |
| } |
| // We didn't handle it, maybe somebody upstairs will. |
| if (theStatus == eventNotHandledErr) { |
| theStatus = [super handleEvent:event handler:handler]; |
| } |
| return theStatus; |
| } |
| |
| @end |
| |
| @implementation GTMCarbonHotKey |
| |
| // Init a HotKey record. In debug version make sure that the selector we are |
| // passed matches what we expect. ( |
| // Arguments: |
| // keyID - id of the hotkey |
| // reference - hotkey reference |
| // target - object we are going to call when the hotkey is hit |
| // action - selector we are going to call on target |
| // userinfo - info for user |
| // whenPressed - do we do it on key down or key up? |
| // Returns: |
| // a hotkey record, or nil on failure |
| - (id)initWithHotKey:(EventHotKeyID)keyID |
| target:(id)target |
| action:(SEL)selector |
| userInfo:(id)userInfo |
| whenPressed:(BOOL)onKeyDown { |
| if ((self = [super init])) { |
| if(!target || !selector) { |
| [self release]; |
| return nil; |
| } |
| id_ = keyID; |
| target_ = [target retain]; |
| userInfo_ = [userInfo retain]; |
| selector_ = selector; |
| onKeyDown_ = onKeyDown; |
| GTMAssertSelectorNilOrImplementedWithReturnTypeAndArguments(target, |
| selector, |
| @encode(void), |
| @encode(id), |
| NULL); |
| } |
| return self; |
| } |
| |
| - (void)dealloc { |
| [target_ release]; |
| [userInfo_ release]; |
| [super dealloc]; |
| } |
| |
| - (NSUInteger)hash { |
| return (NSUInteger)hotKeyRef_; |
| } |
| |
| - (BOOL)isEqual:(id)object { |
| return [object isMemberOfClass:[self class]] |
| && (hotKeyRef_ == [object hotKeyRef]); |
| } |
| |
| // Does this record match key |keyID| |
| // Arguments: |
| // keyID - the id to match against |
| // Returns: |
| // Yes if we match this key id |
| - (BOOL)matchesHotKeyID:(EventHotKeyID)keyID { |
| return (id_.signature == keyID.signature) && (id_.id == keyID.id); |
| } |
| |
| - (BOOL)sendAction { |
| BOOL handled = NO; |
| @try { |
| [target_ performSelector:selector_ withObject:self]; |
| handled = YES; |
| } |
| @catch (NSException * e) { |
| handled = NO; |
| _GTMDevLog(@"Exception fired in hotkey: %@ (%@)", [e name], [e reason]); |
| } // COV_NF_LINE |
| return handled; |
| } |
| |
| - (BOOL)onKeyDown { |
| return onKeyDown_; |
| } |
| |
| - (id)userInfo { |
| return userInfo_; |
| } |
| |
| - (EventHotKeyRef)hotKeyRef { |
| return hotKeyRef_; |
| } |
| |
| - (void)setHotKeyRef:(EventHotKeyRef)ref { |
| hotKeyRef_ = ref; |
| } |
| |
| - (NSString *)description { |
| return [NSString stringWithFormat:@"<%@ %p> - ref %p signature %lu id %lu", |
| [self class], self, hotKeyRef_, |
| (unsigned long)id_.signature, (unsigned long)id_.id]; |
| } |
| |
| @end |
| |
| |
| |