Added `-[NSArray validateAsPropertyList]` and `-[NSDictionary validateAsPropertyList...
[adiumx.git] / Source / PTHotKeyCenter.m
blobbe795791779ad0ad1eae68520952f9773223fd53
1 //
2 //  PTHotKeyCenter.m
3 //  Protein
4 //
5 //  Created by Quentin Carnicelli on Sat Aug 02 2003.
6 //  Copyright (c) 2003 Quentin D. Carnicelli. All rights reserved.
7 //
9 #import "PTHotKeyCenter.h"
10 #import "PTHotKey.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 );
22 @end
24 @implementation PTHotKeyCenter
26 static id _sharedHotKeyCenter = nil;
28 + (PTHotKeyCenter *)sharedCenter
30         if( _sharedHotKeyCenter == nil )
31         {
32                 _sharedHotKeyCenter = [[self alloc] init];
33         }
34         
35         return _sharedHotKeyCenter;
38 - (id)init
40         self = [super init];
41         
42         if( self )
43         {
44                 mHotKeys = [[NSMutableDictionary alloc] init];
45         }
46         
47         return self;
50 - (void)dealloc
52         [mHotKeys release];
53         [super dealloc];
56 #pragma mark -
58 - (BOOL)registerHotKey: (PTHotKey*)hotKey
60         OSStatus err;
61         EventHotKeyID hotKeyID;
62         EventHotKeyRef carbonHotKey;
63         NSValue* key;
65         if( [[self allHotKeys] containsObject: hotKey] == YES )
66                 [self unregisterHotKey: hotKey];
67         
68         if( [[hotKey keyCombo] isValidHotKeyCombo] == NO )
69                 return YES;
70         
71         hotKeyID.signature = 'HCHk';
72         hotKeyID.id = (long)hotKey;
73         
74         err = RegisterEventHotKey(  [[hotKey keyCombo] keyCode],
75                                                                 [[hotKey keyCombo] modifiers],
76                                                                 hotKeyID,
77                                                                 GetEventDispatcherTarget(),
78                                                                 nil,
79                                                                 &carbonHotKey );
81         if( err )
82                 return NO;
84         key = [NSValue valueWithPointer: carbonHotKey];
85         if( hotKey && key )
86                 [mHotKeys setObject: hotKey forKey: key];
88         [self _updateEventHandler];
89         
90         return YES;
93 - (void)unregisterHotKey: (PTHotKey*)hotKey
95         OSStatus err;
96         EventHotKeyRef carbonHotKey;
97         NSValue* key;
99         if( [[self allHotKeys] containsObject: hotKey] == NO )
100                 return;
101         
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];
110         
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];
124         PTHotKey* hotKey;
125         
126         if( !ident )
127                 return nil;
128         
129         while( (hotKey = [hotKeysEnum nextObject]) != nil )
130         {
131                 if( [[hotKey identifier] isEqual: ident] )
132                         return hotKey;
133         }
135         return nil;
138 #pragma mark -
140 - (PTHotKey*)_hotKeyForCarbonHotKey: (EventHotKeyRef)carbonHotKey
142         NSValue* key = [NSValue valueWithPointer: carbonHotKey];
143         return [mHotKeys objectForKey: key];
146 - (EventHotKeyRef)_carbonHotKeyForHotKey: (PTHotKey*)hotKey
148         NSArray* values;
149         NSValue* value;
150         
151         values = [mHotKeys allKeysForObject: hotKey];
152         NSAssert( [values count] == 1, @"Failed to find Carbon Hotkey for HotKey" );
153         
154         value = [values lastObject];
155         
156         return (EventHotKeyRef)[value pointerValue];
159 - (void)_updateEventHandler
161         if( [mHotKeys count] && mEventHandlerInstalled == NO )
162         {
163                 EventTypeSpec eventSpec[2] = {
164                         { kEventClassKeyboard, kEventHotKeyPressed },
165                         { kEventClassKeyboard, kEventHotKeyReleased }
166                 };    
168                 InstallEventHandler( GetEventDispatcherTarget(),
169                                                          (EventHandlerProcPtr)hotKeyEventHandler, 
170                                                          2, eventSpec, nil, nil);
171         
172                 mEventHandlerInstalled = YES;
173         }
176 - (void)_hotKeyDown: (PTHotKey*)hotKey
178         [hotKey invoke];
181 - (void)_hotKeyUp: (PTHotKey*)hotKey
185 - (void)sendEvent: (NSEvent*)event
187         long subType;
188         EventHotKeyRef carbonHotKey;
189         
190         if( [event type] == NSSystemDefined )
191         {
192                 subType = [event subtype];
193                 
194                 if( subType == 6 ) //6 is hot key down
195                 {
196                         carbonHotKey= (EventHotKeyRef)[event data1]; //data1 is our hot key ref
197                         if( carbonHotKey != nil )
198                         {
199                                 PTHotKey* hotKey = [self _hotKeyForCarbonHotKey: carbonHotKey];
200                                 [self _hotKeyDown: hotKey];
201                         }
202                 }
203                 else if( subType == 9 ) //9 is hot key up
204                 {
205                         carbonHotKey= (EventHotKeyRef)[event data1];
206                         if( carbonHotKey != nil )
207                         {
208                                 PTHotKey* hotKey = [self _hotKeyForCarbonHotKey: carbonHotKey];
209                                 [self _hotKeyUp: hotKey];
210                         }
211                 }
212         }
215 - (OSStatus)sendCarbonEvent: (EventRef)event
217         OSStatus err;
218         EventHotKeyID hotKeyID;
219         PTHotKey* hotKey;
221         NSAssert( GetEventClass( event ) == kEventClassKeyboard, @"Unknown event class" );
223         err = GetEventParameter(        event,
224                                                                 kEventParamDirectObject, 
225                                                                 typeEventHotKeyID,
226                                                                 nil,
227                                                                 sizeof(EventHotKeyID),
228                                                                 nil,
229                                                                 &hotKeyID );
230         if( err )
231                 return err;
232         
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 ) )
240         {
241                 case kEventHotKeyPressed:
242                         [self _hotKeyDown: hotKey];
243                 break;
245                 case kEventHotKeyReleased:
246                         [self _hotKeyUp: hotKey];
247                 break;
249                 default:
250                         NSAssert( 0, @"Unknown event kind" );
251                 break;
252         }
253         
254         return noErr;
257 static OSStatus hotKeyEventHandler(EventHandlerCallRef inHandlerRef, EventRef inEvent, void* refCon )
259         return [[PTHotKeyCenter sharedCenter] sendCarbonEvent: inEvent];
262 @end