source: trunk/Cocoa/Pester/Source/NJRHotKeyManager.m@ 312

Last change on this file since 312 was 131, checked in by Nicholas Riley, 22 years ago

PSPreferencesController.[hm]: Added support for registering hot keys;
not the most elegant thing in the world, but much better than it was
in the prototype. Triggered by +readPreferences.

NJRHotKeyField.[hm]: Replaced model components (wow, was that ever
dumb) by NJRHotKey reference, eliminating cumbersome archiving model.
Added accessors for hot key.

NJRHotKeyManager.[hm]: Ported Quentin Carnicelli's HotKeyCenter code
to use NJRHotKey, cleaned up, and removed reverse-engineered pre-10.2
support.

NJRHotKey.[hm]: New. Provides Cocoa-centric storage for
three-component hot keys, mapping from Cocoa to Carbon modifiers.

PSApplication.m: Reorganized. Added invocation of
+[PSPreferencesController readPreferences].

Fixes bug 29.

File size: 6.4 KB
Line 
1//
2// NJRHotKeyManager.m
3// Pester
4//
5// Created by Nicholas Riley on Tue Apr 01 2003.
6// Copyright (c) 2003 Nicholas Riley. All rights reserved.
7//
8
9// based on HotKeyCenter, by Quentin Carnicelli
10// renamed, reorganized, cleaned up, pre-10.2 support removed
11
12#import "NJRHotKeyManager.h"
13#import "NJRHotKey.h"
14#import <Carbon/Carbon.h>
15
16const OSType kHotKeyManagerSignature = 'NHKM';
17
18@interface _NJRHotKeyShortcut : NSObject {
19 @public
20 BOOL isRegistered;
21 EventHotKeyRef hotKeyRef;
22 NJRHotKey *hotKey;
23 id target;
24 SEL action;
25}
26@end
27
28@implementation _NJRHotKeyShortcut
29
30- (void)dealloc;
31{
32 [hotKey release];
33 [target release];
34}
35
36@end
37
38pascal OSErr keyEventHandler(EventHandlerCallRef inHandlerRef, EventRef inEvent, void *refCon);
39
40@interface NJRHotKeyManager (Private)
41- (OSStatus)_handleHotKeyEvent:(EventRef)inEvent;
42- (BOOL)_registerHotKeyIfNeeded:(_NJRHotKeyShortcut *)shortcut;
43- (void)_unregisterHotKeyIfNeeded:(_NJRHotKeyShortcut *)shortcut;
44- (void)_hotKeyDown:(_NJRHotKeyShortcut *)hotKey;
45- (void)_hotKeyUp:(_NJRHotKeyShortcut *)hotKey;
46- (void)_hotKeyDownWithRef:(EventHotKeyRef)ref;
47- (void)_hotKeyUpWithRef:(EventHotKeyRef)ref;
48- (_NJRHotKeyShortcut *)_findShortcutWithRef:(EventHotKeyRef)ref;
49@end
50
51@implementation NJRHotKeyManager
52
53+ (NJRHotKeyManager *)sharedManager;
54{
55 static NJRHotKeyManager *manager = nil;
56
57 if (manager == nil) {
58 manager = [[self alloc] init];
59
60 EventTypeSpec eventSpec[2] = {
61 { kEventClassKeyboard, kEventHotKeyPressed },
62 { kEventClassKeyboard, kEventHotKeyReleased }
63 };
64
65 InstallEventHandler(GetEventDispatcherTarget(),
66 NewEventHandlerUPP((EventHandlerProcPtr) keyEventHandler),
67 2, eventSpec, nil, nil);
68 }
69 return manager;
70}
71
72- (id)init;
73{
74 if ( (self = [super init]) != nil) {
75 shortcutsEnabled = YES;
76 shortcuts = [[NSMutableDictionary alloc] init];
77 }
78
79 return self;
80}
81
82- (void)dealloc;
83{
84 [shortcuts release];
85 [super dealloc];
86}
87
88#pragma mark -
89
90- (BOOL)addShortcutWithIdentifier:(NSString *)identifier hotKey:(NJRHotKey *)hotKey target:(id)target action:(SEL)action;
91{
92 NSParameterAssert(identifier != nil);
93 NSParameterAssert(hotKey != nil);
94 NSParameterAssert(target != nil);
95 NSParameterAssert(action != nil);
96
97 if ([shortcuts objectForKey: identifier] != nil)
98 [self removeShortcutWithIdentifier: identifier];
99
100 _NJRHotKeyShortcut *newShortcut = [[_NJRHotKeyShortcut alloc] init];
101 newShortcut->isRegistered = NO;
102 newShortcut->hotKeyRef = nil;
103 newShortcut->hotKey = [hotKey retain];
104 newShortcut->target = [target retain];
105 newShortcut->action = action;
106
107 [shortcuts setObject: newShortcut forKey: identifier];
108 [newShortcut release];
109
110 return [self _registerHotKeyIfNeeded: newShortcut];
111}
112
113- (void)removeShortcutWithIdentifier:(NSString *)identifier;
114{
115 _NJRHotKeyShortcut *hotKey = [shortcuts objectForKey: identifier];
116
117 if (hotKey == nil) return;
118 [self _unregisterHotKeyIfNeeded: hotKey];
119 [shortcuts removeObjectForKey: identifier];
120}
121
122- (NSArray *)shortcutIdentifiers;
123{
124 return [shortcuts allKeys];
125}
126
127- (NJRHotKey *)hotKeyForShortcutWithIdentifier:(NSString *)identifier;
128{
129 _NJRHotKeyShortcut *hotKey = [shortcuts objectForKey: identifier];
130
131 return (hotKey == nil ? nil : [[hotKey->hotKey retain] autorelease]);
132}
133
134- (void)setShortcutsEnabled:(BOOL)enabled;
135{
136 NSEnumerator *enumerator = [shortcuts objectEnumerator];
137 _NJRHotKeyShortcut *hotKey;
138
139 while ( (hotKey = [enumerator nextObject]) != nil) {
140 if (enabled)
141 [self _registerHotKeyIfNeeded: hotKey];
142 else
143 [self _unregisterHotKeyIfNeeded: hotKey];
144 }
145 shortcutsEnabled = enabled;
146}
147
148- (BOOL)shortcutsEnabled;
149{
150 return shortcutsEnabled;
151}
152
153#pragma mark -
154
155- (OSStatus)_handleHotKeyEvent:(EventRef)inEvent;
156{
157 OSStatus err;
158 EventHotKeyID hotKeyID;
159 _NJRHotKeyShortcut *shortcut;
160
161 NSAssert(GetEventClass(inEvent) == kEventClassKeyboard, @"Unhandled event class");
162
163 if ( (err = GetEventParameter(inEvent, kEventParamDirectObject, typeEventHotKeyID, nil,
164 sizeof(EventHotKeyID), nil, &hotKeyID)) != noErr)
165 return err;
166
167 NSAssert(hotKeyID.signature == kHotKeyManagerSignature, @"Unknown hot key");
168
169 shortcut = (_NJRHotKeyShortcut *)hotKeyID.id;
170 NSAssert(shortcut != nil, @"Got bad hot key");
171
172 switch (GetEventKind(inEvent)) {
173 case kEventHotKeyPressed:
174 [self _hotKeyDown: shortcut];
175 break;
176 case kEventHotKeyReleased:
177 [self _hotKeyUp: shortcut];
178 break;
179 default:
180 break;
181 }
182
183 return noErr;
184}
185
186#pragma mark -
187
188- (BOOL)_registerHotKeyIfNeeded:(_NJRHotKeyShortcut *)shortcut;
189{
190 NJRHotKey *hotKey;
191
192 NSParameterAssert(shortcut != nil);
193
194 hotKey = shortcut->hotKey;
195
196 if (shortcutsEnabled && !(shortcut->isRegistered)) {
197 EventHotKeyID keyID;
198 OSStatus err;
199
200 keyID.signature = kHotKeyManagerSignature;
201 keyID.id = (unsigned long)shortcut;
202 if ( (err = RegisterEventHotKey([hotKey keyCode], [hotKey modifiers], keyID, GetEventDispatcherTarget(), 0, &shortcut->hotKeyRef)) != noErr)
203 return NO;
204
205 shortcut->isRegistered = YES;
206 }
207
208 return YES;
209}
210
211- (void)_unregisterHotKeyIfNeeded:(_NJRHotKeyShortcut *)shortcut;
212{
213 NSParameterAssert(shortcut != nil);
214
215 if (shortcut->isRegistered && shortcut->hotKeyRef != nil)
216 UnregisterEventHotKey(shortcut->hotKeyRef);
217}
218
219- (void)_hotKeyDown:(_NJRHotKeyShortcut *)hotKey;
220{
221 id target = hotKey->target;
222 SEL action = hotKey->action;
223
224 [target performSelector: action withObject: self];
225}
226
227- (void)_hotKeyUp:(_NJRHotKeyShortcut *)hotKey;
228{
229}
230
231- (void)_hotKeyDownWithRef:(EventHotKeyRef)ref;
232{
233 _NJRHotKeyShortcut *hotKey = [self _findShortcutWithRef: ref];
234
235 if (hotKey != nil)
236 [self _hotKeyDown: hotKey];
237}
238
239- (void)_hotKeyUpWithRef:(EventHotKeyRef)ref;
240{
241}
242
243- (_NJRHotKeyShortcut *)_findShortcutWithRef:(EventHotKeyRef)ref;
244{
245 NSEnumerator *enumerator = [shortcuts objectEnumerator];
246 _NJRHotKeyShortcut *hotKey;
247
248 while ( (hotKey = [enumerator nextObject]) != nil) {
249 if (hotKey->hotKeyRef == ref)
250 return hotKey;
251 }
252 return nil;
253}
254
255@end
256
257pascal OSErr keyEventHandler(EventHandlerCallRef inHandlerRef, EventRef inEvent, void *refCon)
258{
259 return [[NJRHotKeyManager sharedManager] _handleHotKeyEvent: inEvent];
260}
Note: See TracBrowser for help on using the repository browser.