5 // Created by Quentin Carnicelli on Sat Aug 02 2003.
6 // Copyright (c) 2003 Quentin D. Carnicelli. All rights reserved.
9 #import "PTHotKeyCenter.h"
11 #import "PTKeyCombo.h"
12 #import <Carbon/Carbon.h>
14 @interface PTHotKeyCenter (Private)
15 - (PTHotKey*)_hotKeyForCarbonHotKey: (EventHotKeyRef)carbonHotKey;
16 - (EventHotKeyRef)_carbonHotKeyForHotKey: (PTHotKey*)hotKey;
18 - (void)_updateEventHandler;
19 - (void)_hotKeyDown: (PTHotKey*)hotKey;
20 - (void)_hotKeyUp: (PTHotKey*)hotKey;
21 static OSStatus hotKeyEventHandler(EventHandlerCallRef inHandlerRef, EventRef inEvent, void* refCon );
24 @implementation PTHotKeyCenter
26 static id _sharedHotKeyCenter = nil;
28 + (PTHotKeyCenter *)sharedCenter
30 if( _sharedHotKeyCenter == nil )
32 _sharedHotKeyCenter = [[self alloc] init];
35 return _sharedHotKeyCenter;
44 mHotKeys = [[NSMutableDictionary alloc] init];
58 - (BOOL)registerHotKey: (PTHotKey*)hotKey
61 EventHotKeyID hotKeyID;
62 EventHotKeyRef carbonHotKey;
65 if( [[self allHotKeys] containsObject: hotKey] == YES )
66 [self unregisterHotKey: hotKey];
68 if( [[hotKey keyCombo] isValidHotKeyCombo] == NO )
71 hotKeyID.signature = 'HCHk';
72 hotKeyID.id = (long)hotKey;
74 err = RegisterEventHotKey( [[hotKey keyCombo] keyCode],
75 [[hotKey keyCombo] modifiers],
77 GetEventDispatcherTarget(),
84 key = [NSValue valueWithPointer: carbonHotKey];
86 [mHotKeys setObject: hotKey forKey: key];
88 [self _updateEventHandler];
93 - (void)unregisterHotKey: (PTHotKey*)hotKey
96 EventHotKeyRef carbonHotKey;
99 if( [[self allHotKeys] containsObject: hotKey] == NO )
102 carbonHotKey = [self _carbonHotKeyForHotKey: hotKey];
103 NSAssert( carbonHotKey != nil, @"" );
105 err = UnregisterEventHotKey( carbonHotKey );
106 //Watch as we ignore 'err':
108 key = [NSValue valueWithPointer: carbonHotKey];
109 [mHotKeys removeObjectForKey: key];
111 [self _updateEventHandler];
113 //See that? Completely ignored
116 - (NSArray*)allHotKeys
118 return [mHotKeys allValues];
121 - (PTHotKey*)hotKeyWithIdentifier: (id)ident
123 NSEnumerator* hotKeysEnum = [[self allHotKeys] objectEnumerator];
129 while( (hotKey = [hotKeysEnum nextObject]) != nil )
131 if( [[hotKey identifier] isEqual: ident] )
140 - (PTHotKey*)_hotKeyForCarbonHotKey: (EventHotKeyRef)carbonHotKey
142 NSValue* key = [NSValue valueWithPointer: carbonHotKey];
143 return [mHotKeys objectForKey: key];
146 - (EventHotKeyRef)_carbonHotKeyForHotKey: (PTHotKey*)hotKey
151 values = [mHotKeys allKeysForObject: hotKey];
152 NSAssert( [values count] == 1, @"Failed to find Carbon Hotkey for HotKey" );
154 value = [values lastObject];
156 return (EventHotKeyRef)[value pointerValue];
159 - (void)_updateEventHandler
161 if( [mHotKeys count] && mEventHandlerInstalled == NO )
163 EventTypeSpec eventSpec[2] = {
164 { kEventClassKeyboard, kEventHotKeyPressed },
165 { kEventClassKeyboard, kEventHotKeyReleased }
168 InstallEventHandler( GetEventDispatcherTarget(),
169 (EventHandlerProcPtr)hotKeyEventHandler,
170 2, eventSpec, nil, nil);
172 mEventHandlerInstalled = YES;
176 - (void)_hotKeyDown: (PTHotKey*)hotKey
181 - (void)_hotKeyUp: (PTHotKey*)hotKey
185 - (void)sendEvent: (NSEvent*)event
188 EventHotKeyRef carbonHotKey;
190 if( [event type] == NSSystemDefined )
192 subType = [event subtype];
194 if( subType == 6 ) //6 is hot key down
196 carbonHotKey= (EventHotKeyRef)[event data1]; //data1 is our hot key ref
197 if( carbonHotKey != nil )
199 PTHotKey* hotKey = [self _hotKeyForCarbonHotKey: carbonHotKey];
200 [self _hotKeyDown: hotKey];
203 else if( subType == 9 ) //9 is hot key up
205 carbonHotKey= (EventHotKeyRef)[event data1];
206 if( carbonHotKey != nil )
208 PTHotKey* hotKey = [self _hotKeyForCarbonHotKey: carbonHotKey];
209 [self _hotKeyUp: hotKey];
215 - (OSStatus)sendCarbonEvent: (EventRef)event
218 EventHotKeyID hotKeyID;
221 NSAssert( GetEventClass( event ) == kEventClassKeyboard, @"Unknown event class" );
223 err = GetEventParameter( event,
224 kEventParamDirectObject,
227 sizeof(EventHotKeyID),
234 NSAssert( hotKeyID.signature == 'HCHk', @"Invalid hot key id" );
235 NSAssert( hotKeyID.id != nil, @"Invalid hot key id" );
237 hotKey = (PTHotKey*)hotKeyID.id;
239 switch( GetEventKind( event ) )
241 case kEventHotKeyPressed:
242 [self _hotKeyDown: hotKey];
245 case kEventHotKeyReleased:
246 [self _hotKeyUp: hotKey];
250 NSAssert( 0, @"Unknown event kind" );
257 static OSStatus hotKeyEventHandler(EventHandlerCallRef inHandlerRef, EventRef inEvent, void* refCon )
259 return [[PTHotKeyCenter sharedCenter] sendCarbonEvent: inEvent];