diff options
| author | Vadim Shpakovski | 2012-07-06 23:10:41 +0300 | 
|---|---|---|
| committer | Vadim Shpakovski | 2012-07-06 23:10:41 +0300 | 
| commit | 018889e57d5c3503379c04a575cfc7a4b90df484 (patch) | |
| tree | bd26398b42a8c77bf853148bd62344eebafd257e | |
| parent | 7eb4408ce34dd831ef279c182672976c8aa3f605 (diff) | |
| download | MASShortcut-018889e57d5c3503379c04a575cfc7a4b90df484.tar.bz2 | |
Adds support for registering global shortcuts with handler.
| -rw-r--r-- | MASShortcut+UserDefaults.h | 9 | ||||
| -rw-r--r-- | MASShortcut+UserDefaults.m | 151 | ||||
| -rw-r--r-- | MASShortcut.h | 3 | ||||
| -rw-r--r-- | MASShortcut.m | 7 | ||||
| -rw-r--r-- | MASShortcutView.h | 1 | ||||
| -rw-r--r-- | MASShortcutView.m | 4 | 
6 files changed, 173 insertions, 2 deletions
| diff --git a/MASShortcut+UserDefaults.h b/MASShortcut+UserDefaults.h new file mode 100644 index 0000000..1b44885 --- /dev/null +++ b/MASShortcut+UserDefaults.h @@ -0,0 +1,9 @@ +#import "MASShortcut.h" + +@interface MASShortcut (UserDefaults) + ++ (void)registerGlobalShortcutWithUserDefaultsKey:(NSString *)userDefaultsKey handler:(void (^)())handler; ++ (void)unregisterGlobalShortcutWithUserDefaultsKey:(NSString *)userDefaultsKey; + + +@end diff --git a/MASShortcut+UserDefaults.m b/MASShortcut+UserDefaults.m new file mode 100644 index 0000000..af3b5af --- /dev/null +++ b/MASShortcut+UserDefaults.m @@ -0,0 +1,151 @@ +#import "MASShortcut+UserDefaults.h" + +@interface MASShortcutHotKey : NSObject + +@property (nonatomic, readonly) NSString *userDefaultsKey; +@property (nonatomic, readonly) void (^handler)(); +@property (nonatomic, readonly) EventHotKeyRef carbonHotKey; +@property (nonatomic, readonly) UInt32 carbonHotKeyID; + +- (id)initWithUserDefaultsKey:(NSString *)userDefaultsKey handler:(void (^)())handler; + ++ (void)uninstallEventHandler; + +@end + +#pragma mark - + +@implementation MASShortcut (UserDefaults) + ++ (NSMutableDictionary *)registeredHotKeys +{ +    static NSMutableDictionary *shared = nil; +    static dispatch_once_t onceToken; +    dispatch_once(&onceToken, ^{ +        shared = [NSMutableDictionary dictionary]; +    }); +    return shared; +} + ++ (void)registerGlobalShortcutWithUserDefaultsKey:(NSString *)userDefaultsKey handler:(void (^)())handler; +{ +    MASShortcutHotKey *hotKey = [[MASShortcutHotKey alloc] initWithUserDefaultsKey:userDefaultsKey handler:handler]; +    [[self registeredHotKeys] setObject:hotKey forKey:userDefaultsKey]; +} + ++ (void)unregisterGlobalShortcutWithUserDefaultsKey:(NSString *)userDefaultsKey +{ +    NSMutableDictionary *registeredHotKeys = [self registeredHotKeys]; +    [registeredHotKeys removeObjectForKey:userDefaultsKey]; +    if (registeredHotKeys.count == 0) { +        [MASShortcutHotKey uninstallEventHandler]; +    } +} + +@end + +#pragma mark - + +@implementation MASShortcutHotKey + +- (id)initWithUserDefaultsKey:(NSString *)userDefaultsKey handler:(void (^)())handler +{ +    self = [super init]; +    if (self) { +        _userDefaultsKey = userDefaultsKey.copy; +        _handler = [handler copy]; +        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(userDefaultsDidChange:) +                                                     name:NSUserDefaultsDidChangeNotification object:[NSUserDefaults standardUserDefaults]]; +        [self installHotKeyFromUserDefaults]; +    } +    return self; +} + +- (void)dealloc +{ +    [[NSNotificationCenter defaultCenter] removeObserver:self name:NSUserDefaultsDidChangeNotification object:[NSUserDefaults standardUserDefaults]]; +    [self uninstallExisitingHotKey]; +} + +#pragma mark - + +- (void)userDefaultsDidChange:(NSNotification *)note +{ +    [self uninstallExisitingHotKey]; +    [self installHotKeyFromUserDefaults]; +} + +#pragma mark - Carbon events + +static EventHandlerRef sEventHandler = NULL; + ++ (BOOL)installCommonEventHandler +{ +    if (sEventHandler == NULL) { +        EventTypeSpec hotKeyPressedSpec = { .eventClass = kEventClassKeyboard, .eventKind = kEventHotKeyPressed }; +        OSStatus status = InstallEventHandler(GetEventDispatcherTarget(), CarbonCallback, 1, &hotKeyPressedSpec, NULL, &sEventHandler); +        if (status != noErr) { +            sEventHandler = NULL; +            return NO; +        } +    } +    return YES; +} + ++ (void)uninstallEventHandler +{ +    if (sEventHandler) { +        RemoveEventHandler(sEventHandler); +        sEventHandler = NULL; +    } +} + +#pragma mark - + +- (void)uninstallExisitingHotKey +{ +    if (_carbonHotKey) { +        UnregisterEventHotKey(_carbonHotKey); +        _carbonHotKey = NULL; +    } +} + +FourCharCode const kMASShortcutSignature = 'MASS'; + +- (void)installHotKeyFromUserDefaults +{ +    NSData *data = [[NSUserDefaults standardUserDefaults] dataForKey:_userDefaultsKey]; +    MASShortcut *shortcut = [MASShortcut shortcutWithData:data]; +    if ((shortcut == nil) || ![[self class] installCommonEventHandler]) return; + +    static UInt32 sCarbonHotKeyID = 0; +    _carbonHotKeyID = ++ sCarbonHotKeyID; +	EventHotKeyID hotKeyID = { .signature = kMASShortcutSignature, .id = _carbonHotKeyID }; +    if (RegisterEventHotKey(shortcut.carbonKeyCode, shortcut.carbonFlags, hotKeyID, GetEventDispatcherTarget(), kEventHotKeyExclusive, &_carbonHotKey) != noErr) { +        _carbonHotKey = NULL; +    } +} + +static OSStatus CarbonCallback(EventHandlerCallRef inHandlerCallRef, EventRef inEvent, void *inUserData) +{ +	if (GetEventClass(inEvent) != kEventClassKeyboard) return noErr; + +	EventHotKeyID hotKeyID; +	OSStatus status = GetEventParameter(inEvent, kEventParamDirectObject, typeEventHotKeyID, NULL, sizeof(hotKeyID), NULL, &hotKeyID); +	if (status != noErr) return status; + +	if (hotKeyID.signature != kMASShortcutSignature) return noErr; + +    [[MASShortcut registeredHotKeys] enumerateKeysAndObjectsUsingBlock:^(id key, MASShortcutHotKey *hotKey, BOOL *stop) { +        if (hotKeyID.id == hotKey.carbonHotKeyID) { +            if (hotKey.handler) { +                hotKey.handler(); +            } +            *stop = YES; +        } +    }]; + +	return noErr; +} + +@end
\ No newline at end of file diff --git a/MASShortcut.h b/MASShortcut.h index 173d994..828769d 100644 --- a/MASShortcut.h +++ b/MASShortcut.h @@ -34,7 +34,8 @@ enum {  @property (nonatomic) NSUInteger keyCode;  @property (nonatomic) NSUInteger modifierFlags; -@property (nonatomic, readonly) NSUInteger carbonFlags; +@property (nonatomic, readonly) UInt32 carbonKeyCode; +@property (nonatomic, readonly) UInt32 carbonFlags;  @property (nonatomic, readonly) NSString *keyCodeString;  @property (nonatomic, readonly) NSString *modifierFlagsString;  @property (nonatomic, readonly) NSData *data; diff --git a/MASShortcut.m b/MASShortcut.m index 0720e9d..4835920 100644 --- a/MASShortcut.m +++ b/MASShortcut.m @@ -62,7 +62,12 @@ NSString *const kMASShortcutModifierFlags = @"ModifierFlags";      _modifierFlags = MASShortcutClear(value);  } -- (NSUInteger)carbonFlags +- (UInt32)carbonKeyCode +{ +    return (self.keyCode == NSNotFound ? 0 : (UInt32)self.keyCode); +} + +- (UInt32)carbonFlags  {      return MASShortcutCarbonFlags(self.modifierFlags);  } diff --git a/MASShortcutView.h b/MASShortcutView.h index 0892c0b..2565d6c 100644 --- a/MASShortcutView.h +++ b/MASShortcutView.h @@ -5,5 +5,6 @@  @property (nonatomic, strong) MASShortcut *shortcutValue;  @property (nonatomic, getter = isRecording) BOOL recording;  @property (nonatomic, getter = isEnabled) BOOL enabled; +@property (nonatomic, copy) void (^shortcutValueChange)(MASShortcutView *sender);  @end diff --git a/MASShortcutView.m b/MASShortcutView.m index 48dde31..00bea5b 100644 --- a/MASShortcutView.m +++ b/MASShortcutView.m @@ -83,6 +83,10 @@      _shortcutValue = shortcutValue;      [self resetToolTips];      [self setNeedsDisplay:YES]; + +    if (self.shortcutValueChange) { +        self.shortcutValueChange(self); +    }  }  - (void)setShortcutPlaceholder:(NSString *)shortcutPlaceholder | 
