diff options
| author | Tomáš Znamenáček | 2014-08-06 18:05:43 +0200 |
|---|---|---|
| committer | Tomáš Znamenáček | 2015-01-07 15:39:39 +0100 |
| commit | 444d1bccb9770738fa4ea40383c23f44a55089c2 (patch) | |
| tree | a4f06e82263b751685e51ee3e1479fd9eebb1d16 /Framework/MASShortcut+UserDefaults.m | |
| parent | d8efb0755ab99ef60411f77fa4b635f466973d0f (diff) | |
| download | MASShortcut-444d1bccb9770738fa4ea40383c23f44a55089c2.tar.bz2 | |
Refactored the shortcut dispatcher and bindings to user defaults.
This is a big change that was hard to split into smaller commits. There’s now
a new class to bind shortcuts to actions, a new class to bind user defaults’
keys to actions, and a new way to associate user defaults with the recorder
control (MASShortcutView). I have also updated the demo app to go with the
changes.
The new class to associate shortcuts with actions is called MASShortcutMonitor.
It wraps the Carbon hotkey magic and offers a simple interface to add a
shortcut along with a block that should be run when the shortcut is pressed.
It’s the lowest-level interface.
Since the usual requirement is to store the shortcuts into user defaults,
there’s also a higher-level interface offered by the MASShortcutBinder class.
That takes a defaults key and associates it with a block. When the shortcut
stored under the defaults key changes, the binder automatically switches to the
new shortcut. The class is a wrapper built atop of the previous one, the
MASShortcutMonitor – it simply adds, updates and removes shortcuts as the
user defaults change.
I have removed the special user defaults integration code from the recorder
control (MASShortcutView) and replaced it with a small Cocoa Bindings shim.
This means that in order to keep the recorder control in sync with the defaults
you just have to call the usual bind:toObject:withKeyPath:options: method,
like this:
[_shortcutView bind:MASShortcutBinding
toObject:[NSUserDefaultsController sharedUserDefaultsController]
withKeyPath[@"values.ExampleDefaultsKey"
options:@{NSValueTransformerNameBindingOption:NSKeyedUnarchiveFromDataTransformerName}];
That’s more verbose than the previous solution, but it’s much cleaner and can
be swept under a convenience call if needed. I might also add a dictionaryValue
property later that would make it possible to bind the value to user defaults
directly, without a transformer, and would enable backward compatibility with
Shortcut Recorder.
Diffstat (limited to 'Framework/MASShortcut+UserDefaults.m')
| -rw-r--r-- | Framework/MASShortcut+UserDefaults.m | 98 |
1 files changed, 0 insertions, 98 deletions
diff --git a/Framework/MASShortcut+UserDefaults.m b/Framework/MASShortcut+UserDefaults.m deleted file mode 100644 index 006c579..0000000 --- a/Framework/MASShortcut+UserDefaults.m +++ /dev/null @@ -1,98 +0,0 @@ -#import "MASShortcut+UserDefaults.h" -#import "MASShortcut+Monitoring.h" - -@interface MASShortcutUserDefaultsHotKey : NSObject - -@property (nonatomic, readonly) NSString *userDefaultsKey; -@property (nonatomic, copy) void (^handler)(); -@property (nonatomic, weak) id monitor; - -- (id)initWithUserDefaultsKey:(NSString *)userDefaultsKey handler:(void (^)())handler; - -@end - -#pragma mark - - -@implementation MASShortcut (UserDefaults) - -+ (NSMutableDictionary *)registeredUserDefaultsHotKeys -{ - static NSMutableDictionary *shared = nil; - static dispatch_once_t onceToken; - dispatch_once(&onceToken, ^{ - shared = [NSMutableDictionary dictionary]; - }); - return shared; -} - -+ (void)registerGlobalShortcutWithUserDefaultsKey:(NSString *)userDefaultsKey handler:(void (^)())handler -{ - MASShortcutUserDefaultsHotKey *hotKey = [[MASShortcutUserDefaultsHotKey alloc] initWithUserDefaultsKey:userDefaultsKey handler:handler]; - [[self registeredUserDefaultsHotKeys] setObject:hotKey forKey:userDefaultsKey]; -} - -+ (void)unregisterGlobalShortcutWithUserDefaultsKey:(NSString *)userDefaultsKey -{ - NSMutableDictionary *registeredHotKeys = [self registeredUserDefaultsHotKeys]; - [registeredHotKeys removeObjectForKey:userDefaultsKey]; -} - -+ (void)setGlobalShortcut:(MASShortcut *)shortcut forUserDefaultsKey:(NSString *)userDefaultsKey -{ - NSData *shortcutData = [NSArchiver archivedDataWithRootObject:shortcut]; - if (shortcutData) - [[NSUserDefaults standardUserDefaults] setObject:shortcutData forKey:userDefaultsKey]; - else - [[NSUserDefaults standardUserDefaults] removeObjectForKey:userDefaultsKey]; -} - -@end - -#pragma mark - - -@implementation MASShortcutUserDefaultsHotKey { - NSString *_observableKeyPath; -} - -void *MASShortcutUserDefaultsContext = &MASShortcutUserDefaultsContext; - -- (id)initWithUserDefaultsKey:(NSString *)userDefaultsKey handler:(void (^)())handler -{ - self = [super init]; - if (self) { - _userDefaultsKey = userDefaultsKey.copy; - _handler = [handler copy]; - _observableKeyPath = [@"values." stringByAppendingString:_userDefaultsKey]; - [[NSUserDefaultsController sharedUserDefaultsController] addObserver:self forKeyPath:_observableKeyPath options:NSKeyValueObservingOptionInitial context:MASShortcutUserDefaultsContext]; - } - return self; -} - -- (void)dealloc -{ - [[NSUserDefaultsController sharedUserDefaultsController] removeObserver:self forKeyPath:_observableKeyPath context:MASShortcutUserDefaultsContext]; - [MASShortcut removeGlobalHotkeyMonitor:self.monitor]; -} - -#pragma mark - - -- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context -{ - if (context == MASShortcutUserDefaultsContext) { - [MASShortcut removeGlobalHotkeyMonitor:self.monitor]; - [self installHotKeyFromUserDefaults]; - } - else { - [super observeValueForKeyPath:keyPath ofObject:object change:change context:context]; - } -} - -- (void)installHotKeyFromUserDefaults -{ - NSData *data = [[NSUserDefaults standardUserDefaults] dataForKey:_userDefaultsKey]; - MASShortcut *shortcut = [NSKeyedUnarchiver unarchiveObjectWithData:data]; - if (shortcut == nil) return; - self.monitor = [MASShortcut addGlobalHotkeyMonitorWithShortcut:shortcut handler:self.handler]; -} - -@end |
