PageRenderTime 118ms CodeModel.GetById 12ms app.highlight 100ms RepoModel.GetById 1ms app.codeStats 0ms

/core/externals/google-toolbox-for-mac/AppKit/GTMCarbonEvent.m

http://macfuse.googlecode.com/
Objective C | 764 lines | 394 code | 98 blank | 272 comment | 50 complexity | be9a9dacce6952e86ad3d7ea234f6bb8 MD5 | raw file
  1//
  2//  GTMCarbonEvent.m
  3//
  4//  Copyright 2006-2008 Google Inc.
  5//
  6//  Licensed under the Apache License, Version 2.0 (the "License"); you may not
  7//  use this file except in compliance with the License.  You may obtain a copy
  8//  of the License at
  9//
 10//  http://www.apache.org/licenses/LICENSE-2.0
 11//
 12//  Unless required by applicable law or agreed to in writing, software
 13//  distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 14//  WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
 15//  License for the specific language governing permissions and limitations under
 16//  the License.
 17//
 18
 19#import "GTMCarbonEvent.h"
 20#import <AppKit/AppKit.h>
 21#import "GTMDebugSelectorValidation.h"
 22#import "GTMTypeCasting.h"
 23
 24// Wrapper for all the info we need about a hotkey that we can store in a
 25// Foundation storage class.
 26@interface GTMCarbonHotKey (GTMCarbonHotKeyPrivate)
 27
 28// Create a HotKey record
 29//  Arguments:
 30//    keyID - id of the hotkey
 31//    target - object we are going to call when the hotkey is hit
 32//    action - selector we are going to call on target
 33//    userInfo - user storage
 34//    whenPressed - do we do it on key down or key up?
 35//  Returns:
 36//    a hotkey record, or nil on failure
 37- (id)initWithHotKey:(EventHotKeyID)keyID
 38              target:(id)target
 39              action:(SEL)selector
 40            userInfo:(id)userInfo
 41         whenPressed:(BOOL)onKeyDown;
 42
 43// Does this record match key |keyID|
 44//  Arguments:
 45//    keyID - the id to match against
 46//  Returns:
 47//    Yes if we match this key id
 48- (BOOL)matchesHotKeyID:(EventHotKeyID)keyID;
 49
 50// Make target perform selector
 51//  Returns:
 52//    Yes if handled
 53- (BOOL)sendAction;
 54
 55- (void)setHotKeyRef:(EventHotKeyRef)ref;
 56@end
 57
 58@implementation GTMCarbonEvent
 59
 60//  Create an event of class |inClass| and kind |inKind|
 61//
 62//  Returns:
 63//    Autoreleased GTMCarbonEvent
 64//
 65+ (id)eventWithClass:(UInt32)inClass kind:(UInt32)kind {
 66  return [[[self alloc] initWithClass:inClass kind:kind] autorelease];
 67}
 68
 69
 70//  Create an event based on |event|. Retains |event|.
 71//
 72//  Returns:
 73//    Autoreleased GTMCarbonEvent
 74//
 75+ (id)eventWithEvent:(EventRef)event {
 76  return [[[self alloc] initWithEvent:event] autorelease];
 77}
 78
 79
 80//  Create an event based on the event currently being handled.
 81//
 82//  Returns:
 83//    Autoreleased GTMCarbonEvent
 84//
 85+ (id)currentEvent {
 86  return [self eventWithEvent:GetCurrentEvent()];
 87}
 88
 89
 90//  Create an event of class |inClass| and kind |inKind|
 91//
 92//  Returns:
 93//    GTMCarbonEvent
 94//
 95- (id)initWithClass:(UInt32)inClass kind:(UInt32)kind {
 96  if ((self = [super init])) {
 97    verify_noerr(CreateEvent(kCFAllocatorDefault, inClass, kind,
 98                             0, kEventAttributeNone, &event_));
 99  }
100  return self;
101}
102
103
104//  Create an event based on |event|. Retains |event|.
105//
106//  Returns:
107//    GTMCarbonEvent
108//
109- (id)initWithEvent:(EventRef)event {
110  if ((self = [super init])) {
111    if (event) {
112      event_ = RetainEvent(event);
113    }
114  }
115  return self;
116}
117
118
119// This does a proper event copy, but ignores the |zone|. No way to do a copy
120// of an event into a specific zone.
121//
122//  Arguments:
123//    zone - the zone to copy to
124//  Returns:
125//    the copied event. nil on failure
126- (id)copyWithZone:(NSZone *)zone {
127  GTMCarbonEvent *carbonEvent = nil;
128  EventRef newEvent = CopyEvent([self event]);
129  if (newEvent) {
130    carbonEvent = [[[self class] allocWithZone:zone] initWithEvent:newEvent];
131    ReleaseEvent(newEvent);
132  }
133  return carbonEvent;
134}
135
136// releases our retained event
137//
138- (void)dealloc {
139  if (event_) {
140    ReleaseEvent(event_);
141    event_ = NULL;
142  }
143  [super dealloc];
144}
145
146// description utliity for debugging
147//
148- (NSString *)description {
149  // Use 8 bytes because stack protection gives us a warning if we use a
150  // smaller buffer.
151  char cls[8];
152  UInt32 kind;
153
154  // Need everything bigendian if we are printing out the class as a "string"
155  *((UInt32 *)cls) = CFSwapInt32HostToBig([self eventClass]);
156  kind = [self eventKind];
157  cls[4] = 0;
158  return [NSString stringWithFormat:@"GTMCarbonEvent '%s' %lu",
159          cls, (unsigned long)kind];
160}
161
162
163//  Get the event's class.
164//
165//  Returns:
166//    event class
167//
168- (UInt32)eventClass {
169  return GetEventClass(event_);
170}
171
172
173//  Get the event's kind.
174//
175//  Returns:
176//    event kind
177//
178- (UInt32)eventKind {
179  return GetEventKind(event_);
180}
181
182
183//  Set the event's time.
184//
185//  Arguments:
186//    time - the time you want associated with the event
187//
188- (void)setTime:(EventTime)eventTime {
189  verify_noerr(SetEventTime(event_, eventTime));
190}
191
192
193//  Get the event's time.
194//
195//  Returns:
196//    the time associated with the event
197//
198- (EventTime)time {
199  return GetEventTime(event_);
200}
201
202
203//  Get the event's eventref for passing to other carbon functions.
204//
205//  Returns:
206//    the event ref associated with the event
207//
208- (EventRef)event {
209  return event_;
210}
211
212
213//  Sends event to an event target with options
214//
215//  Arguments:
216//    target - target to send event to.
217//    options - options to send event. See SendEventToEventTargetWithOptions
218//              for details.
219//
220//  Returns:
221//    OSStatus value.
222//
223- (OSStatus)sendToTarget:(GTMCarbonEventHandler *)target
224                 options:(OptionBits)options {
225  return SendEventToEventTargetWithOptions(event_,
226                                           [target eventTarget], options);
227}
228
229//  Post event to an event queue.
230//
231//  Arguments:
232//    queue - queue to post it to.
233//    priority - priority to post it with
234//
235//  Returns:
236//    OSStatus value.
237//
238- (OSStatus)postToQueue:(EventQueueRef)queue priority:(EventPriority)priority {
239  return PostEventToQueue(queue, event_, priority);
240}
241
242
243//  Post event to current queue with standard priority.
244//
245- (void)postToCurrentQueue {
246  verify_noerr([self postToQueue:GetCurrentEventQueue()
247                        priority:kEventPriorityStandard]);
248}
249
250
251//  Post event to main queue with standard priority.
252//
253- (void)postToMainQueue {
254  verify_noerr([self postToQueue:GetMainEventQueue()
255                        priority:kEventPriorityStandard]);
256}
257
258
259//  Sets (or adds) a parameter to an event. Try not to use this function
260//  directly. Look at the PARAM_TEMPLATE_DECL/DEFN macros below.
261//
262//  Arguments:
263//    name - the parameter name.
264//    type - the parameter type.
265//    size - the size of the data that |data| points to.
266//    data - pointer to the data you want to set the parameter to.
267//
268- (void)setParameterNamed:(EventParamName)name
269                     type:(EventParamType)type
270                     size:(ByteCount)size
271                     data:(const void *)data {
272  verify_noerr(SetEventParameter(event_, name, type, size, data));
273}
274
275
276//  Gets a parameter from an event. Try not to use this function
277//  directly. Look at the PARAM_TEMPLATE_DECL/DEFN macros below.
278//
279//  Arguments:
280//    name - the parameter name.
281//    type - the parameter type.
282//    size - the size of the data that |data| points to.
283//    data - pointer to the buffer that you want to fill with your data.
284//
285//  Returns:
286//    YES is parameter is retrieved successfully. NO if parameter doesn't exist.
287//
288- (BOOL)getParameterNamed:(EventParamName)name
289                     type:(EventParamType)type
290                     size:(ByteCount)size
291                     data:(void *)data {
292  OSStatus status = GetEventParameter(event_, name, type,
293                                      NULL, size, NULL, data);
294  return status == noErr;
295}
296
297
298//  Gets a the size of a parameter from an event.
299//
300//  Arguments:
301//    name - the parameter name.
302//    type - the parameter type.
303//
304//  Returns:
305//    The size of the buffer required to hold the parameter. 0 if parameter
306//    doesn't exist.
307//
308- (ByteCount)sizeOfParameterNamed:(EventParamName)name
309                             type:(EventParamType)type {
310  ByteCount size = 0;
311  verify_noerr(GetEventParameter(event_, name, type, NULL, 0, &size, NULL));
312  return size;
313}
314
315@end
316
317@implementation GTMCarbonEvent (GTMCarbonEventGettersAndSetters)
318GTM_PARAM_TEMPLATE_DEFN(UInt32)
319GTM_PARAM_TEMPLATE_DEFN(EventHotKeyID)
320@end
321
322UInt32 GTMCocoaToCarbonKeyModifiers(NSUInteger inCocoaModifiers) {
323  UInt32 carbModifiers = 0;
324  if (inCocoaModifiers & NSAlphaShiftKeyMask) carbModifiers |= alphaLock;
325  if (inCocoaModifiers & NSShiftKeyMask) carbModifiers |= shiftKey;
326  if (inCocoaModifiers & NSControlKeyMask) carbModifiers |= controlKey;
327  if (inCocoaModifiers & NSAlternateKeyMask) carbModifiers |= optionKey;
328  if (inCocoaModifiers & NSCommandKeyMask) carbModifiers |= cmdKey;
329  return carbModifiers;
330}
331
332NSUInteger GTMCarbonToCocoaKeyModifiers(UInt32 inCarbonModifiers) {
333  NSUInteger nsModifiers = 0;
334  if (inCarbonModifiers & alphaLock) nsModifiers |= NSAlphaShiftKeyMask;
335  if (inCarbonModifiers & shiftKey) nsModifiers |= NSShiftKeyMask;
336  if (inCarbonModifiers & controlKey) nsModifiers |= NSControlKeyMask;
337  if (inCarbonModifiers & optionKey) nsModifiers |= NSAlternateKeyMask;
338  if (inCarbonModifiers & cmdKey) nsModifiers |= NSCommandKeyMask;
339  return nsModifiers;
340}
341
342const OSType kGTMCarbonFrameworkSignature = 'GTM ';
343
344@implementation GTMCarbonEventHandler
345
346// Does our delegate respond to eventHandler:receivedEvent:handler:
347//
348// Returns:
349//  YES if delegate responds to eventHandler:receivedEvent:handler:
350- (BOOL) delegateRespondsToHandleEvent {
351  return delegateRespondsToHandleEvent_;
352}
353
354// Registers the event handler to listen for |events|.
355//
356// Arguments:
357//   events - an array of EventTypeSpec. The events to register for.
358//   count - the number of EventTypeSpecs in events.
359//
360- (void)registerForEvents:(const EventTypeSpec *)events count:(size_t)count {
361  verify_noerr(AddEventTypesToHandler([self eventHandler], count, events));
362}
363
364// Causes the event handler to stop listening for |events|.
365//
366// Arguments:
367//   events - an array of EventTypeSpec. The events to register for.
368//   count - the number of EventTypeSpecs in events.
369//
370- (void)unregisterForEvents:(const EventTypeSpec *)events count:(size_t)count {
371  verify_noerr(RemoveEventTypesFromHandler([self eventHandler], count, events));
372}
373
374// To be overridden by subclasses to respond to events. All subclasses should
375// call [super handleEvent:handler:] if they don't handle the event themselves.
376//
377// Arguments:
378//   event - the event to be handled
379//   handler - the call ref in case you want to call CallNextEventHandler
380//             in your method
381// Returns:
382//   OSStatus - usually either noErr or eventNotHandledErr
383//
384- (OSStatus)handleEvent:(GTMCarbonEvent *)event
385                handler:(EventHandlerCallRef)handler {
386  OSStatus status = eventNotHandledErr;
387  require(event, CantUseParams);
388  require(handler, CantUseParams);
389  require([event event], CantUseParams);
390  status = CallNextEventHandler(handler, [event event]);
391CantUseParams:
392  return status;
393}
394
395// To be overridden by subclasses to return the event target for the class.
396// GTMCarbonEventHandler's implementation returns NULL.
397//
398// Returns:
399//   The event target ref.
400//
401- (EventTargetRef)eventTarget {
402  // Defaults implementation needs to be overridden
403  return NULL;
404}
405
406// C callback for our registered EventHandlerUPP.
407//
408// Arguments:
409//  inHandler - handler given to us from Carbon Event system
410//  inEvent - the event we are handling
411//  inUserData - refcon that we gave to the carbon event system. Is a
412//               GTMCarbonEventHandler in disguise.
413// Returns:
414//  status of event handler
415//
416static OSStatus EventHandler(EventHandlerCallRef inHandler,
417                             EventRef inEvent,
418                             void *inUserData) {
419  GTMCarbonEvent *event = [GTMCarbonEvent eventWithEvent:inEvent];
420  GTMCarbonEventHandler *handler
421    = GTM_STATIC_CAST(GTMCarbonEventHandler, inUserData);
422
423  // First check to see if our delegate cares about this event. If the delegate
424  // handles it (i.e responds to it and does not return eventNotHandledErr) we
425  // do not pass it on to default handling.
426  OSStatus status = eventNotHandledErr;
427  if ([handler delegateRespondsToHandleEvent]) {
428    status = [[handler delegate] gtm_eventHandler:handler
429                                    receivedEvent:event
430                                          handler:inHandler];
431  }
432  if (status == eventNotHandledErr) {
433    status = [handler handleEvent:event handler:inHandler];
434  }
435  return status;
436}
437
438// Gets the underlying EventHandlerRef for that this class wraps.
439//
440// Returns:
441//   The EventHandlerRef this class wraps.
442//
443- (EventHandlerRef)eventHandler {
444  if (!eventHandler_) {
445    static EventHandlerUPP sHandlerProc = NULL;
446    if ( sHandlerProc == NULL ) {
447      sHandlerProc = NewEventHandlerUPP(EventHandler);
448    }
449    verify_noerr(InstallEventHandler([self eventTarget],
450                                     sHandlerProc, 0,
451                                     NULL, self, &eventHandler_));
452  }
453  return eventHandler_;
454}
455
456// Gets the delegate for the handler
457//
458// Returns:
459//   the delegate
460- (id)delegate {
461  return delegate_;
462}
463
464// Sets the delegate for the handler and caches whether it responds to
465// the eventHandler:receivedEvent:handler: selector for performance purposes.
466//
467// Arguments:
468//   delegate - the delegate for the handler
469- (void)setDelegate:(id)delegate {
470  delegate_ = delegate;
471  SEL selector = @selector(gtm_eventHandler:receivedEvent:handler:);
472  delegateRespondsToHandleEvent_ = [delegate respondsToSelector:selector];
473}
474
475@end
476
477@implementation GTMCarbonEventMonitorHandler
478
479+ (GTMCarbonEventMonitorHandler *)sharedEventMonitorHandler {
480  static GTMCarbonEventMonitorHandler *obj = nil;
481  if (!obj) {
482    obj = [[self alloc] init];
483  }
484  return obj;
485}
486
487- (EventTargetRef)eventTarget {
488  return GetEventMonitorTarget();
489}
490
491@end
492
493#if (MAC_OS_X_VERSION_MAX_ALLOWED == MAC_OS_X_VERSION_10_5)
494// Accidentally marked as !LP64 in the 10.5sdk, it's back in the 10.6 sdk.
495// If you remove this decl, please remove it from GTMCarbonEventTest.m as well.
496extern EventTargetRef GetApplicationEventTarget(void);
497#endif  // (MAC_OS_X_VERSION_MAX_ALLOWED == MAC_OS_X_VERSION_10_5)
498
499@implementation GTMCarbonEventApplicationEventHandler
500
501+ (GTMCarbonEventApplicationEventHandler *)sharedApplicationEventHandler {
502  static GTMCarbonEventApplicationEventHandler *obj = nil;
503  if (!obj) {
504    obj = [[self alloc] init];
505  }
506  return obj;
507}
508
509- (EventTargetRef)eventTarget {
510  return GetApplicationEventTarget();
511}
512
513@end
514
515@implementation GTMCarbonEventDispatcherHandler
516
517+ (GTMCarbonEventDispatcherHandler *)sharedEventDispatcherHandler {
518  static GTMCarbonEventDispatcherHandler *obj = nil;
519  if (!obj) {
520    obj = [[self alloc] init];
521  }
522  return obj;
523}
524
525// Register for the events we handle, and set up the dictionaries we need
526// to keep track of the hotkeys and commands that we handle.
527//  Returns:
528//    GTMCarbonApplication or nil on failure
529- (id)init {
530  if ((self = [super init])) {
531    static EventTypeSpec events[] = {
532      { kEventClassKeyboard, kEventHotKeyPressed },
533      { kEventClassKeyboard, kEventHotKeyReleased },
534    };
535    [self registerForEvents:events count:GetEventTypeCount(events)];
536    hotkeys_ = [[NSMutableArray alloc] initWithCapacity:0];
537  }
538  return self;
539}
540
541// COV_NF_START
542// Singleton, we never get released. Just here for completeness.
543- (void)dealloc {
544  [hotkeys_ release];
545  [super dealloc];
546}
547// COV_NF_END
548
549- (EventTargetRef)eventTarget {
550  return GetEventDispatcherTarget();
551}
552
553// Registers a hotkey. When the hotkey is executed by the user, target will be
554// called with selector.
555//  Arguments:
556//    keyCode - the virtual keycode of the hotkey
557//    cocoaModifiers - the modifiers that need to be used with |keyCode|. NB
558//                     that these are cocoa modifiers, so NSCommandKeyMask etc.
559//    target - instance that will get |action| called when the hotkey fires
560//    action - the method to call on |target| when the hotkey fires
561//             action should have the signature - (void)handler:(GTMCarbonEventDispatcherHandler *)handler
562//    userInfo - user storage
563//    onKeyDown - is YES, the hotkey fires on the keydown (usual) otherwise
564//              it fires on the key up.
565//  Returns:
566//    a EventHotKeyRef that you can use with other Carbon functions, or for
567//    unregistering the hotkey. Note that all hotkeys are unregistered
568//    automatically when an app quits. Will be NULL on failure.
569- (GTMCarbonHotKey *)registerHotKey:(NSUInteger)keyCode
570                          modifiers:(NSUInteger)cocoaModifiers
571                             target:(id)target
572                             action:(SEL)selector
573                           userInfo:(id)userInfo
574                        whenPressed:(BOOL)onKeyDown {
575  static UInt32 sCurrentID = 0;
576
577  GTMCarbonHotKey *newKey = nil;
578  EventHotKeyRef theRef = NULL;
579  EventHotKeyID keyID;
580  keyID.signature = kGTMCarbonFrameworkSignature;
581  keyID.id = ++sCurrentID;
582  newKey = [[[GTMCarbonHotKey alloc] initWithHotKey:keyID
583                                             target:target
584                                             action:selector
585                                           userInfo:userInfo
586                                        whenPressed:onKeyDown] autorelease];
587  require(newKey, CantCreateKey);
588  require_noerr_action(RegisterEventHotKey((UInt32)keyCode,
589                                           GTMCocoaToCarbonKeyModifiers(cocoaModifiers),
590                                           keyID,
591                                           [self eventTarget],
592                                           0,
593                                           &theRef),
594                       CantRegisterHotKey, newKey = nil);
595  [newKey setHotKeyRef:theRef];
596  [hotkeys_ addObject:newKey];
597
598CantRegisterHotKey:
599CantCreateKey:
600  return newKey;
601}
602
603// Unregisters a hotkey previously registered with registerHotKey.
604//  Arguments:
605//    keyRef - the EventHotKeyRef to unregister
606- (void)unregisterHotKey:(GTMCarbonHotKey *)keyRef {
607  check([hotkeys_ containsObject:keyRef]);
608  [[keyRef retain] autorelease];
609  [hotkeys_ removeObject:keyRef];
610  verify_noerr(UnregisterEventHotKey([keyRef hotKeyRef]));
611}
612
613// A hotkey has been hit. See if it is one of ours, and if so fire it.
614//  Arguments:
615//    event - the hotkey even that was received
616//  Returns:
617//    Yes if handled.
618- (BOOL)handleHotKeyEvent:(GTMCarbonEvent *)event {
619  EventHotKeyID keyID;
620  BOOL handled = [event getEventHotKeyIDParameterNamed:kEventParamDirectObject
621                                                  data:&keyID];
622  if (handled) {
623    GTMCarbonHotKey *hotkey;
624    GTM_FOREACH_OBJECT(hotkey, hotkeys_) {
625      if ([hotkey matchesHotKeyID:keyID]) {
626        EventKind kind = [event eventKind];
627        BOOL onKeyDown = [hotkey onKeyDown];
628        if ((kind == kEventHotKeyPressed && onKeyDown) ||
629            (kind == kEventHotKeyReleased && !onKeyDown)) {
630          handled = [hotkey sendAction];
631        }
632        break;
633      }
634    }
635  }
636  return handled;
637}
638
639// Currently we handle hotkey and command events here. If we get one of them
640// we dispatch them off to the handlers above. Otherwise we just call up to
641// super.
642//  Arguments:
643//    event - the event to check
644//    handler - the handler call ref
645//  Returns:
646//    OSStatus
647- (OSStatus)handleEvent:(GTMCarbonEvent *)event
648                handler:(EventHandlerCallRef)handler {
649  OSStatus theStatus = eventNotHandledErr;
650  if ([event eventClass] == kEventClassKeyboard) {
651    EventKind kind = [event eventKind];
652    if (kind == kEventHotKeyPressed || kind == kEventHotKeyReleased) {
653      theStatus = [self handleHotKeyEvent:event] ? noErr : eventNotHandledErr;
654    }
655  }
656  // We didn't handle it, maybe somebody upstairs will.
657  if (theStatus == eventNotHandledErr) {
658    theStatus = [super handleEvent:event handler:handler];
659  }
660  return theStatus;
661}
662
663@end
664
665@implementation GTMCarbonHotKey
666
667// Init a HotKey record. In debug version make sure that the selector we are
668// passed matches what we expect. (
669//  Arguments:
670//    keyID - id of the hotkey
671//    reference - hotkey reference
672//    target - object we are going to call when the hotkey is hit
673//    action - selector we are going to call on target
674//    userinfo - info for user
675//    whenPressed - do we do it on key down or key up?
676//  Returns:
677//    a hotkey record, or nil on failure
678- (id)initWithHotKey:(EventHotKeyID)keyID
679              target:(id)target
680              action:(SEL)selector
681            userInfo:(id)userInfo
682         whenPressed:(BOOL)onKeyDown {
683  if ((self = [super init])) {
684    if(!target || !selector) {
685      [self release];
686      return nil;
687    }
688    id_ = keyID;
689    target_ = [target retain];
690    userInfo_ = [userInfo retain];
691    selector_ = selector;
692    onKeyDown_ = onKeyDown;
693    GTMAssertSelectorNilOrImplementedWithReturnTypeAndArguments(target,
694                                                                selector,
695                                                                @encode(void),
696                                                                @encode(id),
697                                                                NULL);
698  }
699  return self;
700}
701
702- (void)dealloc {
703  [target_ release];
704  [userInfo_ release];
705  [super dealloc];
706}
707
708- (NSUInteger)hash {
709  return (NSUInteger)hotKeyRef_;
710}
711
712- (BOOL)isEqual:(id)object {
713  return [object isMemberOfClass:[self class]]
714    && (hotKeyRef_ == [object hotKeyRef]);
715}
716
717// Does this record match key |keyID|
718//  Arguments:
719//    keyID - the id to match against
720//  Returns:
721//    Yes if we match this key id
722- (BOOL)matchesHotKeyID:(EventHotKeyID)keyID {
723  return (id_.signature == keyID.signature) && (id_.id == keyID.id);
724}
725
726- (BOOL)sendAction {
727  BOOL handled = NO;
728  @try {
729    [target_ performSelector:selector_ withObject:self];
730    handled = YES;
731  }
732  @catch (NSException * e) {
733    handled = NO;
734    _GTMDevLog(@"Exception fired in hotkey: %@ (%@)", [e name], [e reason]);
735  }  // COV_NF_LINE
736  return handled;
737}
738
739- (BOOL)onKeyDown {
740  return onKeyDown_;
741}
742
743- (id)userInfo {
744  return userInfo_;
745}
746
747- (EventHotKeyRef)hotKeyRef {
748  return hotKeyRef_;
749}
750
751- (void)setHotKeyRef:(EventHotKeyRef)ref {
752  hotKeyRef_ = ref;
753}
754
755- (NSString *)description {
756  return [NSString stringWithFormat:@"<%@ %p> - ref %p signature %lu id %lu",
757          [self class], self, hotKeyRef_,
758          (unsigned long)id_.signature, (unsigned long)id_.id];
759}
760
761@end
762
763
764