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