1 #import "ITHotKeyCenter.h"
4 #import <Carbon/Carbon.h>
6 @interface ITHotKeyCenter (Private)
7 - (BOOL)_hasCarbonEventSupport;
9 - (ITHotKey *)_hotKeyForCarbonHotKey:(EventHotKeyRef)carbonHotKey;
10 - (EventHotKeyRef)_carbonHotKeyForHotKey:(ITHotKey *)hotKey;
12 - (void)_updateEventHandler;
13 - (void)_hotKeyDown:(ITHotKey *)hotKey;
14 - (void)_hotKeyUp:(ITHotKey *)hotKey;
16 static OSStatus hotKeyEventHandler(EventHandlerCallRef inHandlerRef, EventRef inEvent, void *refCon);
19 @implementation ITHotKeyCenter
21 static ITHotKeyCenter *_sharedHotKeyCenter = nil;
24 if (!_sharedHotKeyCenter) {
25 _sharedHotKeyCenter = [[self alloc] init];
27 return _sharedHotKeyCenter;
31 if ((self = [super init])) {
32 mHotKeys = [[NSMutableDictionary alloc] init];
47 - (void)setEnabled:(BOOL)flag {
51 - (BOOL)registerHotKey:(ITHotKey *)hotKey {
52 EventHotKeyID hotKeyID;
53 EventHotKeyRef carbonHotKey;
56 if ([[self allHotKeys] containsObject:hotKey]) {
57 [self unregisterHotKey:hotKey];
60 if (![[hotKey keyCombo] isValidHotKeyCombo]) {
64 hotKeyID.signature = 'PTHk';
65 hotKeyID.id = (long)hotKey;
67 if (RegisterEventHotKey([[hotKey keyCombo] keyCode], [[hotKey keyCombo] modifiers], hotKeyID, GetEventDispatcherTarget(), nil, &carbonHotKey)) {
71 key = [NSValue valueWithPointer:carbonHotKey];
72 [mHotKeys setObject:hotKey forKey:key];
74 [self _updateEventHandler];
79 - (void)unregisterHotKey:(ITHotKey *)hotKey {
81 EventHotKeyRef carbonHotKey;
84 if (![[self allHotKeys] containsObject:hotKey]) {
88 carbonHotKey = [self _carbonHotKeyForHotKey:hotKey];
89 NSAssert(carbonHotKey, @"");
91 err = UnregisterEventHotKey(carbonHotKey);
93 key = [NSValue valueWithPointer:carbonHotKey];
94 [mHotKeys removeObjectForKey:key];
96 [self _updateEventHandler];
99 - (NSArray *)allHotKeys {
100 return [mHotKeys allValues];
103 - (BOOL)_hasCarbonEventSupport {
104 return (floor(NSAppKitVersionNumber) > NSAppKitVersionNumber10_1);
107 - (ITHotKey *)_hotKeyForCarbonHotKey:(EventHotKeyRef)carbonHotKey {
108 NSValue *key = [NSValue valueWithPointer:carbonHotKey];
109 return [mHotKeys objectForKey:key];
112 - (EventHotKeyRef)_carbonHotKeyForHotKey:(ITHotKey *)hotKey {
116 values = [mHotKeys allKeysForObject:hotKey];
117 NSAssert(([values count] == 1), @"Failed to find Carbon Hotkey for ITHotKey");
119 value = [values lastObject];
121 return (EventHotKeyRef)[value pointerValue];
124 - (void)_updateEventHandler {
125 if (![self _hasCarbonEventSupport]) {
129 if ([mHotKeys count] && !mEventHandlerInstalled) {
130 EventTypeSpec eventSpec[2] = {
131 { kEventClassKeyboard, kEventHotKeyPressed },
132 { kEventClassKeyboard, kEventHotKeyReleased }
135 InstallEventHandler(GetEventDispatcherTarget(), (EventHandlerProcPtr)hotKeyEventHandler, 2, eventSpec, nil, nil);
137 mEventHandlerInstalled = YES;
141 - (void)_hotKeyDown:(ITHotKey *)hotKey {
145 - (void)_hotKeyUp:(ITHotKey *)hotKey {
148 - (void)sendEvent:(NSEvent *)event {
150 EventHotKeyRef carbonHotKey;
156 //We only have to intercept sendEvent to do hot keys on old system versions
157 if ([self _hasCarbonEventSupport]) {
161 if ([event type] == NSSystemDefined) {
162 subType = [event subtype];
164 if (subType == 6) { //6 is hot key down
165 carbonHotKey = (EventHotKeyRef)[event data1]; //data1 is our hot key ref
167 ITHotKey *hotKey = [self _hotKeyForCarbonHotKey:carbonHotKey];
168 [self _hotKeyDown:hotKey];
170 } else if (subType == 9) { //9 is hot key up
171 carbonHotKey = (EventHotKeyRef)[event data1];
173 ITHotKey *hotKey = [self _hotKeyForCarbonHotKey:carbonHotKey];
174 [self _hotKeyUp:hotKey];
180 - (OSStatus)sendCarbonEvent:(EventRef)event {
182 EventHotKeyID hotKeyID;
189 NSAssert([self _hasCarbonEventSupport], @"");
190 NSAssert((GetEventClass(event) == kEventClassKeyboard), @"Unknown event class");
192 if ((err = GetEventParameter(event, kEventParamDirectObject, typeEventHotKeyID, nil, sizeof(EventHotKeyID), nil, &hotKeyID))) {
196 NSAssert((hotKeyID.signature == 'PTHk'), @"Invalid hot key id");
197 NSAssert((hotKeyID.id != nil), @"Invalid hot key id");
199 hotKey = (ITHotKey *)hotKeyID.id;
201 switch (GetEventKind(event)) {
202 case kEventHotKeyPressed:
203 [self _hotKeyDown:hotKey];
205 case kEventHotKeyReleased:
206 [self _hotKeyUp:hotKey];
209 NSAssert(NO, @"Unknown event kind");
216 static OSStatus hotKeyEventHandler(EventHandlerCallRef inHandlerRef, EventRef inEvent, void *refCon) {
217 return [[ITHotKeyCenter sharedCenter] sendCarbonEvent:inEvent];