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

Last change on this file since 554 was 355, checked in by Nicholas Riley, 12 years ago

English.lproj/MainMenu.nib: Modernize menu and alarm set dialog
layout. Use keyed archiving (10.2+) nib format.

Info-Pester.plist: Moved from old PBX project.

NJRFSObjectSelector.m: Bug fixes from code sent to Joey: remove
incorrect usage of tryToPerform:with:; fix logic error in menu
construction. Work around Cocoa's deciding that the menu font size
needs adjustment when it doesn't - so the menu font size now matches
the button font size, though the position is still off. Don't pop up
a menu if we're disabled. Use IconRefs? for menu icons, though not
(yet) for the button icon.

NJRHistoryTrackingComboBox.m: Remove item height adjustment
workaround; it now makes the items too tall.

NJRHotKey.m: Add a missing [super dealloc] caught by current GCC.

NJRHotKeyField.m: Add a missing [super dealloc] caught by current GCC.

NJRHotKeyManager.m: Add a missing [super dealloc] caught by current
GCC.

NJRIntervalField.m: Fix some type errors.

NJRQTMediaPopUpButton.m: Replace SoundFileManager? SPI usage, which
doesn't work in Leopard anyway, with manual enumeration of system
sounds. Start migration to QTKit. Use IconRefs? for menu icons.

NJRReadMeController.m: Change source encoding to UTF-8.

NJRSoundManager.m: Fix a type error.

NJRVoicePopUpButton.m: Change source encoding to UTF-8.

NSMenuItem-NJRExtensions.[hm]: Code from ICeCoffEE to use IconRefs? for
menu item icons.

PSAlarm.m: Change source encoding to UTF-8.

PSAlarms.m: Fix a signedness mismatch.

PSAlarmsController.m: Change source encoding to UTF-8.

PSAlarmSetController.m: Set keyboard focus after unchecking "Do
script:" and "Play" checkboxes.

PSAlerts.m: Add a missing [super dealloc] caught by current GCC. Fix
a memory leak in property list serialization.

PSPowerManager.[hm]: There's now API for scheduling wakeups; use it
(the old code asserted on startup). To fix: removing scheduled
wakeup. Fix a small type-checking error.

PSPreferencesController.m: Add a missing [super dealloc] caught by
current GCC.

PSScriptAlert.m: Change source encoding to UTF-8.

PSTimeDateEditor.m: Fix a tiny, and one-time, memory leak.

PSTimer.m: Update for new PSPowerManager API.

Pester.pbproj: Deleted; now supporting OS X 10.4+ (up from 10.1,
aiee.)

Pester.xcodeproj: Xcode 2.4+ project, upgraded targets, etc.

SoundFileManager?.h: Deleted; this SPI no longer exists in Leopard and
possibly earlier.

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