aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorVadim Shpakovski2012-07-06 23:10:41 +0300
committerVadim Shpakovski2012-07-06 23:10:41 +0300
commit018889e57d5c3503379c04a575cfc7a4b90df484 (patch)
treebd26398b42a8c77bf853148bd62344eebafd257e
parent7eb4408ce34dd831ef279c182672976c8aa3f605 (diff)
downloadMASShortcut-018889e57d5c3503379c04a575cfc7a4b90df484.tar.bz2
Adds support for registering global shortcuts with handler.
-rw-r--r--MASShortcut+UserDefaults.h9
-rw-r--r--MASShortcut+UserDefaults.m151
-rw-r--r--MASShortcut.h3
-rw-r--r--MASShortcut.m7
-rw-r--r--MASShortcutView.h1
-rw-r--r--MASShortcutView.m4
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