diff options
| -rw-r--r-- | DDHotKey.xcodeproj/project.pbxproj | 11 | ||||
| -rw-r--r-- | DDHotKeyAppDelegate.h | 2 | ||||
| -rw-r--r-- | DDHotKeyAppDelegate.m | 7 | ||||
| -rw-r--r-- | DDHotKeyCenter.h | 29 | ||||
| -rw-r--r-- | DDHotKeyCenter.m | 122 |
5 files changed, 138 insertions, 33 deletions
diff --git a/DDHotKey.xcodeproj/project.pbxproj b/DDHotKey.xcodeproj/project.pbxproj index 0bdda50..2b47832 100644 --- a/DDHotKey.xcodeproj/project.pbxproj +++ b/DDHotKey.xcodeproj/project.pbxproj @@ -153,7 +153,14 @@ isa = PBXProject; buildConfigurationList = C01FCF4E08A954540054247B /* Build configuration list for PBXProject "DDHotKey" */; compatibilityVersion = "Xcode 3.1"; + developmentRegion = English; hasScannedForEncodings = 1; + knownRegions = ( + English, + Japanese, + French, + German, + ); mainGroup = 29B97314FDCFA39411CA2CEA /* DDHotKey */; projectDirPath = ""; projectRoot = ""; @@ -249,7 +256,7 @@ GCC_WARN_UNUSED_VARIABLE = YES; ONLY_ACTIVE_ARCH = YES; PREBINDING = NO; - SDKROOT = macosx10.6; + SDKROOT = macosx; }; name = Debug; }; @@ -261,7 +268,7 @@ GCC_WARN_ABOUT_RETURN_TYPE = YES; GCC_WARN_UNUSED_VARIABLE = YES; PREBINDING = NO; - SDKROOT = macosx10.6; + SDKROOT = macosx; }; name = Release; }; diff --git a/DDHotKeyAppDelegate.h b/DDHotKeyAppDelegate.h index 2b775dc..08cac15 100644 --- a/DDHotKeyAppDelegate.h +++ b/DDHotKeyAppDelegate.h @@ -10,7 +10,7 @@ #import <Cocoa/Cocoa.h> -@interface DDHotKeyAppDelegate : NSObject <NSApplicationDelegate> { +@interface DDHotKeyAppDelegate : NSObject /*<NSApplicationDelegate>*/ { NSWindow *window; NSTextView *output; } diff --git a/DDHotKeyAppDelegate.m b/DDHotKeyAppDelegate.m index 8857060..3a38951 100644 --- a/DDHotKeyAppDelegate.m +++ b/DDHotKeyAppDelegate.m @@ -43,6 +43,7 @@ [self addOutput:@"Unable to register hotkey for example 1"]; } else { [self addOutput:@"Registered hotkey for example 1"]; + [self addOutput:[NSString stringWithFormat:@"Registered: %@", [c registeredHotKeys]]]; } [c release]; } @@ -54,11 +55,13 @@ [self addOutput:@"Unable to register hotkey for example 2"]; } else { [self addOutput:@"Registered hotkey for example 2"]; + [self addOutput:[NSString stringWithFormat:@"Registered: %@", [c registeredHotKeys]]]; } [c release]; } - (IBAction) registerExample3:(id)sender { +#if NS_BLOCKS_AVAILABLE [self addOutput:@"Attempting to register hotkey for example 3"]; DDHotKeyCenter * c = [[DDHotKeyCenter alloc] init]; int theAnswer = 42; @@ -71,8 +74,12 @@ [self addOutput:@"Unable to register hotkey for example 3"]; } else { [self addOutput:@"Registered hotkey for example 3"]; + [self addOutput:[NSString stringWithFormat:@"Registered: %@", [c registeredHotKeys]]]; } [c release]; +#else + NSRunAlertPanel(@"Blocks not available", @"This example requires the 10.6 SDK", @"OK", nil, nil); +#endif } - (IBAction) unregisterExample1:(id)sender { diff --git a/DDHotKeyCenter.h b/DDHotKeyCenter.h index 1991a31..6274b36 100644 --- a/DDHotKeyCenter.h +++ b/DDHotKeyCenter.h @@ -15,6 +15,22 @@ typedef void (^DDHotKeyTask)(NSEvent*); #endif +@interface DDHotKey : NSObject + +@property (nonatomic, readonly, retain) id target; +@property (nonatomic, readonly) SEL action; +@property (nonatomic, readonly, retain) id object; +#if NS_BLOCKS_AVAILABLE +@property (nonatomic, readonly, copy) DDHotKeyTask task; +#endif + +@property (nonatomic, readonly) unsigned short keyCode; +@property (nonatomic, readonly) NSUInteger modifierFlags; + +@end + +#pragma mark - + @interface DDHotKeyCenter : NSObject { } @@ -37,11 +53,16 @@ typedef void (^DDHotKeyTask)(NSEvent*); /** See if a hotkey exists with the specified keycode and modifier flags. - NOTE: this will only check among hotkeys you have explicitly registered. This does not check all globally registered hotkeys. + NOTE: this will only check among hotkeys you have explicitly registered with DDHotKeyCenter. This does not check all globally registered hotkeys. */ - (BOOL) hasRegisteredHotKeyWithKeyCode:(unsigned short)keyCode modifierFlags:(NSUInteger)flags; /** + Unregister a specific hotkey + */ +- (void) unregisterHotKey:(DDHotKey *)hotKey; + +/** Unregister all hotkeys with a specific target */ - (void) unregisterHotKeysWithTarget:(id)target; @@ -56,4 +77,10 @@ typedef void (^DDHotKeyTask)(NSEvent*); */ - (void) unregisterHotKeyWithKeyCode:(unsigned short)keyCode modifierFlags:(NSUInteger)flags; +/** + Returns a set of currently registered hotkeys + **/ +- (NSSet *) registeredHotKeys; + @end + diff --git a/DDHotKeyCenter.m b/DDHotKeyCenter.m index 22d3c1c..68b4c5c 100644 --- a/DDHotKeyCenter.m +++ b/DDHotKeyCenter.m @@ -10,6 +10,7 @@ #import "DDHotKeyCenter.h" #import <Carbon/Carbon.h> +#import <objc/runtime.h> #pragma mark Private Global Declarations @@ -17,10 +18,48 @@ static NSMutableSet * _registeredHotKeys = nil; static UInt32 _nextHotKeyID = 1; OSStatus dd_hotKeyHandler(EventHandlerCallRef nextHandler, EventRef theEvent, void * userData); NSUInteger dd_translateModifierFlags(NSUInteger flags); +NSString* dd_stringifyModifierFlags(NSUInteger flags); #pragma mark DDHotKey -@interface DDHotKey : NSObject { +@implementation DDHotKey + +- (id) target { return nil; } +- (SEL) action { return nil; } +- (id) object { return nil; } +- (unsigned short) keyCode { return 0; } +- (NSUInteger) modifierFlags { return 0; } + +#if NS_BLOCKS_AVAILABLE +- (DDHotKeyTask) task { return nil; } +#endif + +- (NSUInteger) hash { + return [self keyCode] + [self modifierFlags]; +} + +- (BOOL) isEqual:(id)object { + BOOL equal = NO; + if ([object isKindOfClass:[DDHotKey class]]) { + equal = ([object keyCode] == [self keyCode]); + equal &= ([object modifierFlags] == [self modifierFlags]); + } + return equal; +} + +- (NSString *) description { + NSString * flags = dd_stringifyModifierFlags([self modifierFlags]); + NSString * invokes = @"(block)"; + if ([self target] != nil && [self action] != nil) { + invokes = [NSString stringWithFormat:@"[%@ %@]", [self target], NSStringFromSelector([self action])]; + } + return [NSString stringWithFormat:@"%@\n\t(key: %hu\n\tflags: %@\n\tinvokes: %@)", [super description], [self keyCode], flags, invokes]; +} + +@end + +@interface _DDHotKey : DDHotKey { + @private id target; SEL action; id object; @@ -35,16 +74,17 @@ NSUInteger dd_translateModifierFlags(NSUInteger flags); NSValue * hotKeyRef; } -@property (retain) id target; -@property SEL action; -@property (retain) id object; +@property (nonatomic, retain) id target; +@property (nonatomic) SEL action; +@property (nonatomic, retain) id object; +@property (nonatomic) unsigned short keyCode; +@property (nonatomic) NSUInteger modifierFlags; +@property (nonatomic) UInt32 hotKeyID; +@property (nonatomic, retain) NSValue * hotKeyRef; + #if NS_BLOCKS_AVAILABLE -@property (copy) DDHotKeyTask task; +@property (nonatomic, copy) DDHotKeyTask task; #endif -@property unsigned short keyCode; -@property NSUInteger modifierFlags; -@property UInt32 hotKeyID; -@property (retain) NSValue * hotKeyRef; - (void) invokeWithEvent:(NSEvent *)event; - (BOOL) registerHotKey; @@ -52,9 +92,14 @@ NSUInteger dd_translateModifierFlags(NSUInteger flags); @end -@implementation DDHotKey +@implementation _DDHotKey + +@synthesize target, action, object, keyCode, modifierFlags, hotKeyID, hotKeyRef; +#if NS_BLOCKS_AVAILABLE +@synthesize task; +#endif -@synthesize target, action, object, task, keyCode, modifierFlags, hotKeyID, hotKeyRef; +- (Class) class { return [DDHotKey class]; } - (void) invokeWithEvent:(NSEvent *)event { if (target != nil && action != nil && [target respondsToSelector:action]) { @@ -77,7 +122,8 @@ NSUInteger dd_translateModifierFlags(NSUInteger flags); keyID.id = _nextHotKeyID; EventHotKeyRef carbonHotKey; - OSStatus err = RegisterEventHotKey(keyCode, modifierFlags, keyID, GetEventDispatcherTarget(), 0, &carbonHotKey); + NSUInteger flags = dd_translateModifierFlags(modifierFlags); + OSStatus err = RegisterEventHotKey(keyCode, flags, keyID, GetEventDispatcherTarget(), 0, &carbonHotKey); //error registering hot key if (err != 0) { return NO; } @@ -114,7 +160,7 @@ NSUInteger dd_translateModifierFlags(NSUInteger flags); @implementation DDHotKeyCenter + (void) initialize { - if (_registeredHotKeys == nil) { + if (self == [DDHotKeyCenter class] && _registeredHotKeys == nil) { _registeredHotKeys = [[NSMutableSet alloc] init]; _nextHotKeyID = 1; EventTypeSpec eventSpec; @@ -129,7 +175,7 @@ NSUInteger dd_translateModifierFlags(NSUInteger flags); } - (BOOL) hasRegisteredHotKeyWithKeyCode:(unsigned short)keyCode modifierFlags:(NSUInteger)flags { - NSPredicate * predicate = [NSPredicate predicateWithFormat:@"keyCode = %hu AND modifierFlags = %lu", keyCode, dd_translateModifierFlags(flags)]; + NSPredicate * predicate = [NSPredicate predicateWithFormat:@"keyCode = %hu AND modifierFlags = %lu", keyCode, flags]; return ([[self hotKeysMatchingPredicate:predicate] count] > 0); } @@ -138,13 +184,10 @@ NSUInteger dd_translateModifierFlags(NSUInteger flags); //we can't add a new hotkey if something already has this combo if ([self hasRegisteredHotKeyWithKeyCode:keyCode modifierFlags:flags]) { return NO; } - //translate the flags - NSUInteger modifierFlags = dd_translateModifierFlags(flags); - - DDHotKey * newHotKey = [[DDHotKey alloc] init]; + _DDHotKey * newHotKey = [[_DDHotKey alloc] init]; [newHotKey setTask:task]; [newHotKey setKeyCode:keyCode]; - [newHotKey setModifierFlags:modifierFlags]; + [newHotKey setModifierFlags:flags]; BOOL success = [newHotKey registerHotKey]; if (success) { @@ -160,16 +203,13 @@ NSUInteger dd_translateModifierFlags(NSUInteger flags); //we can't add a new hotkey if something already has this combo if ([self hasRegisteredHotKeyWithKeyCode:keyCode modifierFlags:flags]) { return NO; } - //translate the flags - NSUInteger modifierFlags = dd_translateModifierFlags(flags); - //build the hotkey object: - DDHotKey * newHotKey = [[DDHotKey alloc] init]; + _DDHotKey * newHotKey = [[_DDHotKey alloc] init]; [newHotKey setTarget:target]; [newHotKey setAction:action]; [newHotKey setObject:object]; [newHotKey setKeyCode:keyCode]; - [newHotKey setModifierFlags:modifierFlags]; + [newHotKey setModifierFlags:flags]; BOOL success = [newHotKey registerHotKey]; if (success) { @@ -185,10 +225,18 @@ NSUInteger dd_translateModifierFlags(NSUInteger flags); NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init]; NSSet * matches = [self hotKeysMatchingPredicate:predicate]; [_registeredHotKeys minusSet:matches]; - for (DDHotKey * key in matches) { + [matches makeObjectsPerformSelector:@selector(unregisterHotKey)]; + [pool release]; +} + +- (void) unregisterHotKey:(DDHotKey *)hotKey { + if (object_getClass(hotKey) == [_DDHotKey class]) { + _DDHotKey * key = (_DDHotKey *)hotKey; + [_registeredHotKeys removeObject:key]; [key unregisterHotKey]; + } else { + [NSException raise:NSInvalidArgumentException format:@"Invalid hotkey"]; } - [pool release]; } - (void) unregisterHotKeysWithTarget:(id)target { @@ -202,10 +250,14 @@ NSUInteger dd_translateModifierFlags(NSUInteger flags); } - (void) unregisterHotKeyWithKeyCode:(unsigned short)keyCode modifierFlags:(NSUInteger)flags { - NSPredicate * predicate = [NSPredicate predicateWithFormat:@"keyCode = %hu AND modifierFlags = %lu", keyCode, dd_translateModifierFlags(flags)]; + NSPredicate * predicate = [NSPredicate predicateWithFormat:@"keyCode = %hu AND modifierFlags = %lu", keyCode, flags]; [self unregisterHotKeysMatchingPredicate:predicate]; } +- (NSSet *) registeredHotKeys { + return [self hotKeysMatchingPredicate:[NSPredicate predicateWithFormat:@"hotKeyRef != NULL"]]; +} + @end OSStatus dd_hotKeyHandler(EventHandlerCallRef nextHandler, EventRef theEvent, void * userData) { @@ -218,7 +270,7 @@ OSStatus dd_hotKeyHandler(EventHandlerCallRef nextHandler, EventRef theEvent, vo NSSet * matchingHotKeys = [_registeredHotKeys filteredSetUsingPredicate:[NSPredicate predicateWithFormat:@"hotKeyID = %u", keyID]]; if ([matchingHotKeys count] > 1) { NSLog(@"ERROR!"); } - DDHotKey * matchingHotKey = [matchingHotKeys anyObject]; + _DDHotKey * matchingHotKey = [matchingHotKeys anyObject]; NSEvent * event = [NSEvent eventWithEventRef:theEvent]; NSEvent * keyEvent = [NSEvent keyEventWithType:NSKeyUp @@ -246,4 +298,16 @@ NSUInteger dd_translateModifierFlags(NSUInteger flags) { if ((flags & NSShiftKeyMask) > 0) { newFlags |= shiftKey; } if ((flags & NSAlternateKeyMask) > 0) { newFlags |= optionKey; } return newFlags; -}
\ No newline at end of file +} + +NSString* dd_stringifyModifierFlags(NSUInteger flags) { + NSMutableArray * bits = [NSMutableArray array]; + if ((flags & NSControlKeyMask) > 0) { [bits addObject:@"NSControlKeyMask"]; } + if ((flags & NSCommandKeyMask) > 0) { [bits addObject:@"NSCommandKeyMask"]; } + if ((flags & NSShiftKeyMask) > 0) { [bits addObject:@"NSShiftKeyMask"]; } + if ((flags & NSAlternateKeyMask) > 0) { [bits addObject:@"NSAlternateKeyMask"]; } + if ([bits count] > 0) { + return [NSString stringWithFormat:@"(%@)", [bits componentsJoinedByString:@" | "]]; + } + return @"ERROR: No valid flags"; +} |
