diff options
| author | Vadim Shpakovski | 2012-09-19 12:43:39 +0300 | 
|---|---|---|
| committer | Vadim Shpakovski | 2012-09-19 12:43:39 +0300 | 
| commit | 4099b62587959708bd02d1c49ec1c8fa39448cf4 (patch) | |
| tree | bf5a851450f9795286d374d49c2a0f11d2318114 | |
| parent | 243aee3038ed23c7f8b96f54871bae00a3be8a41 (diff) | |
| download | MASShortcut-4099b62587959708bd02d1c49ec1c8fa39448cf4.tar.bz2 | |
Isolates monitoring code from data.1.1
| -rw-r--r-- | MASShortcut+Monitoring.h | 8 | ||||
| -rw-r--r-- | MASShortcut+Monitoring.m | 158 | ||||
| -rw-r--r-- | MASShortcut+UserDefaults.m | 1 | ||||
| -rw-r--r-- | MASShortcut.h | 3 | ||||
| -rw-r--r-- | MASShortcut.m | 155 | 
5 files changed, 167 insertions, 158 deletions
| diff --git a/MASShortcut+Monitoring.h b/MASShortcut+Monitoring.h new file mode 100644 index 0000000..aa8f224 --- /dev/null +++ b/MASShortcut+Monitoring.h @@ -0,0 +1,8 @@ +#import "MASShortcut.h" + +@interface MASShortcut (Monitoring) + ++ (id)addGlobalHotkeyMonitorWithShortcut:(MASShortcut *)shortcut handler:(void (^)())handler; ++ (void)removeGlobalHotkeyMonitor:(id)monitor; + +@end diff --git a/MASShortcut+Monitoring.m b/MASShortcut+Monitoring.m new file mode 100644 index 0000000..1460f6b --- /dev/null +++ b/MASShortcut+Monitoring.m @@ -0,0 +1,158 @@ +#import "MASShortcut+Monitoring.h" + +NSMutableDictionary *MASRegisteredHotKeys(); +BOOL InstallCommonEventHandler(); +void UninstallEventHandler(); +void InstallHotkeyWithShortcut(MASShortcut *shortcut, UInt32 *outCarbonHotKeyID, EventHotKeyRef *outCarbonHotKey); + +#pragma mark - + +@interface MASShortcutHotKey : NSObject + +@property (nonatomic, readonly) MASShortcut *shortcut; +@property (nonatomic, readonly, copy) void (^handler)(); +@property (nonatomic, readonly) EventHotKeyRef carbonHotKey; +@property (nonatomic, readonly) UInt32 carbonHotKeyID; + +- (id)initWithShortcut:(MASShortcut *)shortcut handler:(void (^)())handler; + +@end + +#pragma mark - + +@implementation MASShortcut (Monitoring) + ++ (id)addGlobalHotkeyMonitorWithShortcut:(MASShortcut *)shortcut handler:(void (^)())handler +{ +    NSString *monitor = [NSString stringWithFormat:@"%p: %@", shortcut, shortcut.description]; +    MASShortcutHotKey *hotKey = [[MASShortcutHotKey alloc] initWithShortcut:shortcut handler:handler]; +    [MASRegisteredHotKeys() setObject:hotKey forKey:monitor]; +    return monitor; +} + ++ (void)removeGlobalHotkeyMonitor:(id)monitor +{ +    if (monitor == nil) return; +    NSMutableDictionary *registeredHotKeys = MASRegisteredHotKeys(); +    [registeredHotKeys removeObjectForKey:monitor]; +    if (registeredHotKeys.count == 0) { +        UninstallEventHandler(); +    } +} + +@end + +#pragma mark - + +@implementation MASShortcutHotKey + +@synthesize carbonHotKeyID = _carbonHotKeyID; +@synthesize handler = _handler; +@synthesize shortcut = _shortcut; +@synthesize carbonHotKey = _carbonHotKey; + +#pragma mark - + +- (id)initWithShortcut:(MASShortcut *)shortcut handler:(void (^)())handler +{ +    self = [super init]; +    if (self) { +        _shortcut = shortcut; +        _handler = [handler copy]; +        InstallHotkeyWithShortcut(shortcut, &_carbonHotKeyID, &_carbonHotKey); +    } +    return self; +} + +- (void)dealloc +{ +    [self uninstallExisitingHotKey]; +} + +- (void)uninstallExisitingHotKey +{ +    if (_carbonHotKey) { +        UnregisterEventHotKey(_carbonHotKey); +        _carbonHotKey = NULL; +    } +} + +@end + +#pragma mark - Carbon magic + +NSMutableDictionary *MASRegisteredHotKeys() +{ +    static NSMutableDictionary *shared = nil; +    static dispatch_once_t onceToken; +    dispatch_once(&onceToken, ^{ +        shared = [NSMutableDictionary dictionary]; +    }); +    return shared; +} + +#pragma mark - + +FourCharCode const kMASShortcutSignature = 'MASS'; + +void InstallHotkeyWithShortcut(MASShortcut *shortcut, UInt32 *outCarbonHotKeyID, EventHotKeyRef *outCarbonHotKey) +{ +    if ((shortcut == nil) || !InstallCommonEventHandler()) return; + +    static UInt32 sCarbonHotKeyID = 0; +	EventHotKeyID hotKeyID = { .signature = kMASShortcutSignature, .id = ++ sCarbonHotKeyID }; +    EventHotKeyRef carbonHotKey = NULL; +    if (RegisterEventHotKey(shortcut.carbonKeyCode, shortcut.carbonFlags, hotKeyID, GetEventDispatcherTarget(), kEventHotKeyExclusive, &carbonHotKey) != noErr) { +        carbonHotKey = NULL; +    } + +    if (outCarbonHotKeyID) *outCarbonHotKeyID = hotKeyID.id; +    if (outCarbonHotKey) *outCarbonHotKey = carbonHotKey; +} + +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; + +    [MASRegisteredHotKeys() enumerateKeysAndObjectsUsingBlock:^(id key, MASShortcutHotKey *hotKey, BOOL *stop) { +        if (hotKeyID.id == hotKey.carbonHotKeyID) { +            if (hotKey.handler) { +                hotKey.handler(); +            } +            *stop = YES; +        } +    }]; + +	return noErr; +} + +#pragma mark - + +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; +    } +} diff --git a/MASShortcut+UserDefaults.m b/MASShortcut+UserDefaults.m index 38d3707..3bdbab9 100644 --- a/MASShortcut+UserDefaults.m +++ b/MASShortcut+UserDefaults.m @@ -1,4 +1,5 @@  #import "MASShortcut+UserDefaults.h" +#import "MASShortcut+Monitoring.h"  @interface MASShortcutUserDefaultsHotKey : NSObject diff --git a/MASShortcut.h b/MASShortcut.h index a5c8fa9..3c6c109 100644 --- a/MASShortcut.h +++ b/MASShortcut.h @@ -51,7 +51,4 @@ enum {  - (BOOL)isTakenError:(NSError **)error; -+ (id)addGlobalHotkeyMonitorWithShortcut:(MASShortcut *)shortcut handler:(void (^)())handler; -+ (void)removeGlobalHotkeyMonitor:(id)monitor; -  @end diff --git a/MASShortcut.m b/MASShortcut.m index fd9250b..ca5a1ae 100644 --- a/MASShortcut.m +++ b/MASShortcut.m @@ -3,26 +3,6 @@  NSString *const kMASShortcutKeyCode = @"KeyCode";  NSString *const kMASShortcutModifierFlags = @"ModifierFlags"; -NSMutableDictionary *MASRegisteredHotKeys(); -BOOL InstallCommonEventHandler(); -void UninstallEventHandler(); -void InstallHotkeyWithShortcut(MASShortcut *shortcut, UInt32 *outCarbonHotKeyID, EventHotKeyRef *outCarbonHotKey); - -#pragma mark - - -@interface MASShortcutHotKey : NSObject - -@property (nonatomic, readonly) MASShortcut *shortcut; -@property (nonatomic, readonly, copy) void (^handler)(); -@property (nonatomic, readonly) EventHotKeyRef carbonHotKey; -@property (nonatomic, readonly) UInt32 carbonHotKeyID; - -- (id)initWithShortcut:(MASShortcut *)shortcut handler:(void (^)())handler; - -@end - -#pragma mark - -  @implementation MASShortcut {      NSUInteger _keyCode; // NSNotFound if empty      NSUInteger _modifierFlags; // 0 if empty @@ -325,139 +305,4 @@ void InstallHotkeyWithShortcut(MASShortcut *shortcut, UInt32 *outCarbonHotKeyID,      return [self isKeyEquivalent:self.keyCodeStringForKeyEquivalent flags:self.modifierFlags takenInMenu:[NSApp mainMenu] error:outError];  } -#pragma mark - Global monitoring - -+ (id)addGlobalHotkeyMonitorWithShortcut:(MASShortcut *)shortcut handler:(void (^)())handler -{ -    NSString *monitor = [NSString stringWithFormat:@"%p: %@", shortcut, shortcut.description]; -    MASShortcutHotKey *hotKey = [[MASShortcutHotKey alloc] initWithShortcut:shortcut handler:handler]; -    [MASRegisteredHotKeys() setObject:hotKey forKey:monitor]; -    return monitor; -} - -+ (void)removeGlobalHotkeyMonitor:(id)monitor -{ -    if (monitor == nil) return; -    NSMutableDictionary *registeredHotKeys = MASRegisteredHotKeys(); -    [registeredHotKeys removeObjectForKey:monitor]; -    if (registeredHotKeys.count == 0) { -        UninstallEventHandler(); -    } -} - -@end - -#pragma mark - - -@implementation MASShortcutHotKey - -@synthesize carbonHotKeyID = _carbonHotKeyID; -@synthesize handler = _handler; -@synthesize shortcut = _shortcut; -@synthesize carbonHotKey = _carbonHotKey; - -#pragma mark - - -- (id)initWithShortcut:(MASShortcut *)shortcut handler:(void (^)())handler -{ -    self = [super init]; -    if (self) { -        _shortcut = shortcut; -        _handler = [handler copy]; -        InstallHotkeyWithShortcut(shortcut, &_carbonHotKeyID, &_carbonHotKey); -    } -    return self; -} - -- (void)dealloc -{ -    [self uninstallExisitingHotKey]; -} - -- (void)uninstallExisitingHotKey -{ -    if (_carbonHotKey) { -        UnregisterEventHotKey(_carbonHotKey); -        _carbonHotKey = NULL; -    } -} -  @end - -#pragma mark - Carbon magic - -NSMutableDictionary *MASRegisteredHotKeys() -{ -    static NSMutableDictionary *shared = nil; -    static dispatch_once_t onceToken; -    dispatch_once(&onceToken, ^{ -        shared = [NSMutableDictionary dictionary]; -    }); -    return shared; -} - -#pragma mark - - -FourCharCode const kMASShortcutSignature = 'MASS'; - -void InstallHotkeyWithShortcut(MASShortcut *shortcut, UInt32 *outCarbonHotKeyID, EventHotKeyRef *outCarbonHotKey) -{ -    if ((shortcut == nil) || !InstallCommonEventHandler()) return; - -    static UInt32 sCarbonHotKeyID = 0; -	EventHotKeyID hotKeyID = { .signature = kMASShortcutSignature, .id = ++ sCarbonHotKeyID }; -    EventHotKeyRef carbonHotKey = NULL; -    if (RegisterEventHotKey(shortcut.carbonKeyCode, shortcut.carbonFlags, hotKeyID, GetEventDispatcherTarget(), kEventHotKeyExclusive, &carbonHotKey) != noErr) { -        carbonHotKey = NULL; -    } - -    if (outCarbonHotKeyID) *outCarbonHotKeyID = hotKeyID.id; -    if (outCarbonHotKey) *outCarbonHotKey = carbonHotKey; -} - -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; - -    [MASRegisteredHotKeys() enumerateKeysAndObjectsUsingBlock:^(id key, MASShortcutHotKey *hotKey, BOOL *stop) { -        if (hotKeyID.id == hotKey.carbonHotKeyID) { -            if (hotKey.handler) { -                hotKey.handler(); -            } -            *stop = YES; -        } -    }]; - -	return noErr; -} - -#pragma mark - - -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; -    } -} | 
