diff options
| author | Dave DeLong | 2010-11-14 09:36:09 -0700 | 
|---|---|---|
| committer | Dave DeLong | 2010-11-14 09:36:09 -0700 | 
| commit | d02e7a9a02bf580ab82a404a6ff5fdc5ce2f1ebb (patch) | |
| tree | fed4d9bd632956ca2b2864de41ba933a9f741093 | |
| parent | 3907cfe61dc13daa38b779f7596a424222c1d74c (diff) | |
| download | DDHotKey-d02e7a9a02bf580ab82a404a6ff5fdc5ce2f1ebb.tar.bz2 | |
Cleanup; provided a readonly way to iterate registered hotkeys
| -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"; +} | 
