diff options
| -rw-r--r-- | MASShortcut+Monitoring.m | 7 | ||||
| -rw-r--r-- | MASShortcut+UserDefaults.h | 8 | ||||
| -rw-r--r-- | MASShortcut+UserDefaults.m | 87 | ||||
| -rw-r--r-- | MASShortcut.m | 10 | ||||
| -rw-r--r-- | MASShortcutView+UserDefaults.h | 7 | ||||
| -rw-r--r-- | MASShortcutView+UserDefaults.m | 128 | ||||
| -rw-r--r-- | MASShortcutView.h | 17 | ||||
| -rw-r--r-- | MASShortcutView.m | 428 | 
8 files changed, 9 insertions, 683 deletions
| diff --git a/MASShortcut+Monitoring.m b/MASShortcut+Monitoring.m index 1460f6b..51787c2 100644 --- a/MASShortcut+Monitoring.m +++ b/MASShortcut+Monitoring.m @@ -25,7 +25,7 @@ void InstallHotkeyWithShortcut(MASShortcut *shortcut, UInt32 *outCarbonHotKeyID,  + (id)addGlobalHotkeyMonitorWithShortcut:(MASShortcut *)shortcut handler:(void (^)())handler  {      NSString *monitor = [NSString stringWithFormat:@"%p: %@", shortcut, shortcut.description]; -    MASShortcutHotKey *hotKey = [[MASShortcutHotKey alloc] initWithShortcut:shortcut handler:handler]; +    MASShortcutHotKey *hotKey = [[[MASShortcutHotKey alloc] initWithShortcut:shortcut handler:handler] autorelease];      [MASRegisteredHotKeys() setObject:hotKey forKey:monitor];      return monitor;  } @@ -57,7 +57,7 @@ void InstallHotkeyWithShortcut(MASShortcut *shortcut, UInt32 *outCarbonHotKeyID,  {      self = [super init];      if (self) { -        _shortcut = shortcut; +        _shortcut = [shortcut retain];          _handler = [handler copy];          InstallHotkeyWithShortcut(shortcut, &_carbonHotKeyID, &_carbonHotKey);      } @@ -67,6 +67,7 @@ void InstallHotkeyWithShortcut(MASShortcut *shortcut, UInt32 *outCarbonHotKeyID,  - (void)dealloc  {      [self uninstallExisitingHotKey]; +    [super dealloc];  }  - (void)uninstallExisitingHotKey @@ -86,7 +87,7 @@ NSMutableDictionary *MASRegisteredHotKeys()      static NSMutableDictionary *shared = nil;      static dispatch_once_t onceToken;      dispatch_once(&onceToken, ^{ -        shared = [NSMutableDictionary dictionary]; +        shared = [[NSMutableDictionary alloc] init];      });      return shared;  } diff --git a/MASShortcut+UserDefaults.h b/MASShortcut+UserDefaults.h deleted file mode 100644 index 0c7f14e..0000000 --- a/MASShortcut+UserDefaults.h +++ /dev/null @@ -1,8 +0,0 @@ -#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 deleted file mode 100644 index 3bdbab9..0000000 --- a/MASShortcut+UserDefaults.m +++ /dev/null @@ -1,87 +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]; -} - -@end - -#pragma mark - - -@implementation MASShortcutUserDefaultsHotKey - -@synthesize monitor = _monitor; -@synthesize handler = _handler; -@synthesize userDefaultsKey = _userDefaultsKey; - -#pragma mark - - -- (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]]; -    [MASShortcut removeGlobalHotkeyMonitor:self.monitor]; -} - -#pragma mark - - -- (void)userDefaultsDidChange:(NSNotification *)note -{ -    [MASShortcut removeGlobalHotkeyMonitor:self.monitor]; -    [self installHotKeyFromUserDefaults]; -} - -- (void)installHotKeyFromUserDefaults -{ -    NSData *data = [[NSUserDefaults standardUserDefaults] dataForKey:_userDefaultsKey]; -    MASShortcut *shortcut = [MASShortcut shortcutWithData:data]; -    if (shortcut == nil) return; -    self.monitor = [MASShortcut addGlobalHotkeyMonitorWithShortcut:shortcut handler:self.handler]; -} - -@end diff --git a/MASShortcut.m b/MASShortcut.m index ca5a1ae..5bb039d 100644 --- a/MASShortcut.m +++ b/MASShortcut.m @@ -42,12 +42,12 @@ NSString *const kMASShortcutModifierFlags = @"ModifierFlags";  + (MASShortcut *)shortcutWithKeyCode:(NSUInteger)code modifierFlags:(NSUInteger)flags  { -    return [[self alloc] initWithKeyCode:code modifierFlags:flags]; +    return [[[self alloc] initWithKeyCode:code modifierFlags:flags] autorelease];  }  + (MASShortcut *)shortcutWithEvent:(NSEvent *)event  { -    return [[self alloc] initWithKeyCode:event.keyCode modifierFlags:event.modifierFlags]; +    return [[[self alloc] initWithKeyCode:event.keyCode modifierFlags:event.modifierFlags] autorelease];  }  + (MASShortcut *)shortcutWithData:(NSData *)data @@ -195,7 +195,7 @@ NSString *const kMASShortcutModifierFlags = @"ModifierFlags";      if (keystroke.length) {          static NSMutableCharacterSet *validChars = nil;          if (validChars == nil) { -            validChars = [[NSMutableCharacterSet alloc] init]; +            validChars = [[[NSMutableCharacterSet alloc] init] autorelease];              [validChars formUnionWithCharacterSet:[NSCharacterSet alphanumericCharacterSet]];              [validChars formUnionWithCharacterSet:[NSCharacterSet punctuationCharacterSet]];              [validChars formUnionWithCharacterSet:[NSCharacterSet symbolCharacterSet]]; @@ -286,8 +286,8 @@ NSString *const kMASShortcutModifierFlags = @"ModifierFlags";              CFNumberRef code = CFDictionaryGetValue(hotKeyInfo, kHISymbolicHotKeyCode);              CFNumberRef flags = CFDictionaryGetValue(hotKeyInfo, kHISymbolicHotKeyModifiers); -            if (([(__bridge NSNumber *)code unsignedIntegerValue] == self.keyCode) && -                ([(__bridge NSNumber *)flags unsignedIntegerValue] == self.carbonFlags)) { +            if (([(NSNumber *)code unsignedIntegerValue] == self.keyCode) && +                ([(NSNumber *)flags unsignedIntegerValue] == self.carbonFlags)) {                  if (outError) {                      NSString *description = NSLocalizedString(@"This combination cannot be used used because it is already used by a system-wide " diff --git a/MASShortcutView+UserDefaults.h b/MASShortcutView+UserDefaults.h deleted file mode 100644 index 05d3c5b..0000000 --- a/MASShortcutView+UserDefaults.h +++ /dev/null @@ -1,7 +0,0 @@ -#import "MASShortcutView.h" - -@interface MASShortcutView (UserDefaults) - -@property (nonatomic, copy) NSString *associatedUserDefaultsKey; - -@end diff --git a/MASShortcutView+UserDefaults.m b/MASShortcutView+UserDefaults.m deleted file mode 100644 index 42a2379..0000000 --- a/MASShortcutView+UserDefaults.m +++ /dev/null @@ -1,128 +0,0 @@ -#import "MASShortcutView+UserDefaults.h" -#import "MASShortcut.h" -#import <objc/runtime.h> - -@interface MASShortcutDefaultsObserver : NSObject - -@property (nonatomic, readonly) NSString *userDefaultsKey; -@property (nonatomic, readonly, weak) MASShortcutView *shortcutView; - -- (id)initWithShortcutView:(MASShortcutView *)shortcutView userDefaultsKey:(NSString *)userDefaultsKey; - -@end - -#pragma mark - - -@implementation MASShortcutView (UserDefaults) - -void *kDefaultsObserver = &kDefaultsObserver; - -- (NSString *)associatedUserDefaultsKey -{ -    MASShortcutDefaultsObserver *defaultsObserver = objc_getAssociatedObject(self, kDefaultsObserver); -    return defaultsObserver.userDefaultsKey; -} - -- (void)setAssociatedUserDefaultsKey:(NSString *)associatedUserDefaultsKey -{ -    // First, stop observing previous shortcut view -    objc_setAssociatedObject(self, kDefaultsObserver, nil, OBJC_ASSOCIATION_RETAIN_NONATOMIC); - -    // Next, start observing current shortcut view -    MASShortcutDefaultsObserver *defaultsObserver = [[MASShortcutDefaultsObserver alloc] initWithShortcutView:self userDefaultsKey:associatedUserDefaultsKey]; -    objc_setAssociatedObject(self, kDefaultsObserver, defaultsObserver, OBJC_ASSOCIATION_RETAIN_NONATOMIC); -} - -@end - -#pragma mark - - -@implementation MASShortcutDefaultsObserver { -    MASShortcut *_originalShortcut; -    BOOL _internalPreferenceChange; -    BOOL _internalShortcutChange; -} - -@synthesize userDefaultsKey = _userDefaultsKey; -@synthesize shortcutView = _shortcutView; - -#pragma mark - - -- (id)initWithShortcutView:(MASShortcutView *)shortcutView userDefaultsKey:(NSString *)userDefaultsKey -{ -    self = [super init]; -    if (self) { -        _originalShortcut = shortcutView.shortcutValue; -        _shortcutView = shortcutView; -        _userDefaultsKey = userDefaultsKey.copy; -        [self startObservingShortcutView]; -    } -    return self; -} - -- (void)dealloc -{ -    // __weak _shortcutView is not yet deallocated because it refers MASShortcutDefaultsObserver -    [self stopObservingShortcutView]; -} - -#pragma mark - - -void *kShortcutValueObserver = &kShortcutValueObserver; - -- (void)startObservingShortcutView -{ -    // Read initial shortcut value from user preferences -    NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; -    NSData *data = [defaults dataForKey:_userDefaultsKey]; -    _shortcutView.shortcutValue = [MASShortcut shortcutWithData:data]; - -    // Observe user preferences to update shortcut value when it changed -    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(userDefaultsDidChange:) name:NSUserDefaultsDidChangeNotification object:defaults]; - -    // Observe the keyboard shortcut that user inputs by hand -    [_shortcutView addObserver:self forKeyPath:@"shortcutValue" options:0 context:kShortcutValueObserver]; -} - -- (void)userDefaultsDidChange:(NSNotification *)note -{ -    // Ignore notifications posted from -[self observeValueForKeyPath:] -    if (_internalPreferenceChange) return; - -    _internalShortcutChange = YES; -    NSData *data = [note.object dataForKey:_userDefaultsKey]; -    _shortcutView.shortcutValue = [MASShortcut shortcutWithData:data]; -    _internalShortcutChange = NO; -} - -- (void)stopObservingShortcutView -{ -    // Stop observing keyboard hotkeys entered by user in the shortcut view -    [_shortcutView removeObserver:self forKeyPath:@"shortcutValue" context:kShortcutValueObserver]; - -    // Stop observing user preferences -    [[NSNotificationCenter defaultCenter] removeObserver:self name:NSUserDefaultsDidChangeNotification object:[NSUserDefaults standardUserDefaults]]; - -    // Restore original hotkey in the shortcut view -    _shortcutView.shortcutValue = _originalShortcut; -} - -- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context -{ -    if (context == kShortcutValueObserver) { -        if (_internalShortcutChange) return; -        MASShortcut *shortcut = [object valueForKey:keyPath]; -        _internalPreferenceChange = YES; - -        NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults]; -        [defaults setObject:(shortcut.data ?: [NSKeyedArchiver archivedDataWithRootObject:nil]) forKey:_userDefaultsKey]; -        [defaults synchronize]; - -        _internalPreferenceChange = NO; -    } -    else { -        [super observeValueForKeyPath:keyPath ofObject:object change:change context:context]; -    } -} - -@end diff --git a/MASShortcutView.h b/MASShortcutView.h deleted file mode 100644 index 5259123..0000000 --- a/MASShortcutView.h +++ /dev/null @@ -1,17 +0,0 @@ -@class MASShortcut; - -typedef enum { -    MASShortcutViewAppearanceDefault = 0,  // Height = 19 px -    MASShortcutViewAppearanceTexturedRect, // Height = 25 px -    MASShortcutViewAppearanceRounded       // Height = 43 px -} MASShortcutViewAppearance; - -@interface MASShortcutView : NSView - -@property (nonatomic, strong) MASShortcut *shortcutValue; -@property (nonatomic, getter = isRecording) BOOL recording; -@property (nonatomic, getter = isEnabled) BOOL enabled; -@property (nonatomic, copy) void (^shortcutValueChange)(MASShortcutView *sender); -@property (nonatomic) MASShortcutViewAppearance appearance; - -@end diff --git a/MASShortcutView.m b/MASShortcutView.m deleted file mode 100644 index 27e6ae7..0000000 --- a/MASShortcutView.m +++ /dev/null @@ -1,428 +0,0 @@ -#import "MASShortcutView.h" -#import "MASShortcut.h" - -#define HINT_BUTTON_WIDTH 23.0 -#define BUTTON_FONT_SIZE 11.0 -#define SEGMENT_CHROME_WIDTH 6.0 - -#pragma mark - - -@interface MASShortcutView () // Private accessors - -@property (nonatomic, getter = isHinting) BOOL hinting; -@property (nonatomic, copy) NSString *shortcutPlaceholder; - -@end - -#pragma mark - - -@implementation MASShortcutView { -    NSButtonCell *_shortcutCell; -    NSInteger _shortcutToolTipTag; -    NSInteger _hintToolTipTag; -    NSTrackingArea *_hintArea; -} - -@synthesize enabled = _enabled; -@synthesize hinting = _hinting; -@synthesize shortcutValue = _shortcutValue; -@synthesize shortcutPlaceholder = _shortcutPlaceholder; -@synthesize shortcutValueChange = _shortcutValueChange; -@synthesize recording = _recording; - -#pragma mark - - -- (id)initWithFrame:(CGRect)frameRect -{ -    self = [super initWithFrame:frameRect]; -    if (self) { -        _shortcutCell = [[NSButtonCell alloc] init]; -        _shortcutCell.buttonType = NSPushOnPushOffButton; -        _shortcutCell.font = [[NSFontManager sharedFontManager] convertFont:_shortcutCell.font toSize:BUTTON_FONT_SIZE]; -        _enabled = YES; -        [self resetShortcutCellStyle]; -    } -    return self; -} - -- (void)dealloc -{ -    [self activateEventMonitoring:NO]; -    [self activateResignObserver:NO]; -} - -#pragma mark - Public accessors - -- (void)setEnabled:(BOOL)flag -{ -    if (_enabled != flag) { -        _enabled = flag; -        [self updateTrackingAreas]; -        self.recording = NO; -        [self setNeedsDisplay:YES]; -    } -} - -- (void)setAppearance:(MASShortcutViewAppearance)appearance -{ -    if (_appearance != appearance) { -        _appearance = appearance; -        [self resetShortcutCellStyle]; -        [self setNeedsDisplay:YES]; -    } -} - -- (void)resetShortcutCellStyle -{ -    switch (_appearance) { -        case MASShortcutViewAppearanceDefault: { -            _shortcutCell.bezelStyle = NSRoundRectBezelStyle; -            break; -        } -        case MASShortcutViewAppearanceTexturedRect: { -            _shortcutCell.bezelStyle = NSTexturedRoundedBezelStyle; -            break; -        } -        case MASShortcutViewAppearanceRounded: { -            _shortcutCell.bezelStyle = NSRoundedBezelStyle; -            break; -        } -    } -} - -- (void)setRecording:(BOOL)flag -{ -    // Only one recorder can be active at the moment -    static MASShortcutView *currentRecorder = nil; -    if (flag && (currentRecorder != self)) { -        currentRecorder.recording = NO; -        currentRecorder = flag ? self : nil; -    } -     -    // Only enabled view supports recording -    if (flag && !self.enabled) return; -     -    if (_recording != flag) { -        _recording = flag; -        self.shortcutPlaceholder = nil; -        [self resetToolTips]; -        [self activateEventMonitoring:_recording]; -        [self activateResignObserver:_recording]; -        [self setNeedsDisplay:YES]; -    } -} - -- (void)setShortcutValue:(MASShortcut *)shortcutValue -{ -    _shortcutValue = shortcutValue; -    [self resetToolTips]; -    [self setNeedsDisplay:YES]; - -    if (self.shortcutValueChange) { -        self.shortcutValueChange(self); -    } -} - -- (void)setShortcutPlaceholder:(NSString *)shortcutPlaceholder -{ -    _shortcutPlaceholder = shortcutPlaceholder.copy; -    [self setNeedsDisplay:YES]; -} - -#pragma mark - Drawing - -- (BOOL)isFlipped -{ -    return YES; -} - -- (void)drawInRect:(CGRect)frame withTitle:(NSString *)title alignment:(NSTextAlignment)alignment state:(NSInteger)state -{ -    _shortcutCell.title = title; -    _shortcutCell.alignment = alignment; -    _shortcutCell.state = state; -    _shortcutCell.enabled = self.enabled; - -    switch (_appearance) { -        case MASShortcutViewAppearanceDefault: { -            [_shortcutCell drawWithFrame:frame inView:self]; -            break; -        } -        case MASShortcutViewAppearanceTexturedRect: { -            [_shortcutCell drawWithFrame:CGRectOffset(frame, 0.0, 1.0) inView:self]; -            break; -        } -        case MASShortcutViewAppearanceRounded: { -            [_shortcutCell drawWithFrame:CGRectOffset(frame, 0.0, 1.0) inView:self]; -            break; -        } -    } -} - -- (void)drawRect:(CGRect)dirtyRect -{ -    if (self.shortcutValue) { -        [self drawInRect:self.bounds withTitle:MASShortcutChar(self.recording ? kMASShortcutGlyphEscape : kMASShortcutGlyphDeleteLeft) -               alignment:NSRightTextAlignment state:NSOffState]; -         -        CGRect shortcutRect; -        [self getShortcutRect:&shortcutRect hintRect:NULL]; -        NSString *title = (self.recording -                           ? (_hinting -                              ? NSLocalizedString(@"Use Old Shortuct", @"Cancel action button for non-empty shortcut in recording state") -                              : (self.shortcutPlaceholder.length > 0 -                                 ? self.shortcutPlaceholder -                                 : NSLocalizedString(@"Type New Shortcut", @"Non-empty shortcut button in recording state"))) -                           : _shortcutValue ? _shortcutValue.description : @""); -        [self drawInRect:shortcutRect withTitle:title alignment:NSCenterTextAlignment state:self.isRecording ? NSOnState : NSOffState]; -    } -    else { -        if (self.recording) -        { -            [self drawInRect:self.bounds withTitle:MASShortcutChar(kMASShortcutGlyphEscape) alignment:NSRightTextAlignment state:NSOffState]; -             -            CGRect shortcutRect; -            [self getShortcutRect:&shortcutRect hintRect:NULL]; -            NSString *title = (_hinting -                               ? NSLocalizedString(@"Cancel", @"Cancel action button in recording state") -                               : (self.shortcutPlaceholder.length > 0 -                                  ? self.shortcutPlaceholder -                                  : NSLocalizedString(@"Type Shortcut", @"Empty shortcut button in recording state"))); -            [self drawInRect:shortcutRect withTitle:title alignment:NSCenterTextAlignment state:NSOnState]; -        } -        else -        { -            [self drawInRect:self.bounds withTitle:NSLocalizedString(@"Record Shortcut", @"Empty shortcut button in normal state") -                   alignment:NSCenterTextAlignment state:NSOffState]; -        } -    } -} - -#pragma mark - Mouse handling - -- (void)getShortcutRect:(CGRect *)shortcutRectRef hintRect:(CGRect *)hintRectRef -{ -    CGRect shortcutRect, hintRect; -    CGFloat hintButtonWidth = HINT_BUTTON_WIDTH; -    switch (self.appearance) { -        case MASShortcutViewAppearanceTexturedRect: hintButtonWidth += 2.0; break; -        case MASShortcutViewAppearanceRounded: hintButtonWidth += 3.0; break; -        default: break; -    } -    CGRectDivide(self.bounds, &hintRect, &shortcutRect, hintButtonWidth, CGRectMaxXEdge); -    if (shortcutRectRef)  *shortcutRectRef = shortcutRect; -    if (hintRectRef) *hintRectRef = hintRect; -} - -- (BOOL)locationInShortcutRect:(CGPoint)location -{ -    CGRect shortcutRect; -    [self getShortcutRect:&shortcutRect hintRect:NULL]; -    return CGRectContainsPoint(shortcutRect, [self convertPoint:location fromView:nil]); -} - -- (BOOL)locationInHintRect:(CGPoint)location -{ -    CGRect hintRect; -    [self getShortcutRect:NULL hintRect:&hintRect]; -    return CGRectContainsPoint(hintRect, [self convertPoint:location fromView:nil]); -} - -- (void)mouseDown:(NSEvent *)event -{ -    if (self.enabled) { -        if (self.shortcutValue) { -            if (self.recording) { -                if ([self locationInHintRect:event.locationInWindow]) { -                    self.recording = NO; -                } -            } -            else { -                if ([self locationInShortcutRect:event.locationInWindow]) { -                    self.recording = YES; -                } -                else { -                    self.shortcutValue = nil; -                } -            } -        } -        else { -            if (self.recording) { -                if ([self locationInHintRect:event.locationInWindow]) { -                    self.recording = NO; -                } -            } -            else { -                self.recording = YES; -            } -        } -    } -    else { -        [super mouseDown:event]; -    } -} - -#pragma mark - Handling mouse over - -- (void)updateTrackingAreas -{ -    [super updateTrackingAreas]; -     -    if (_hintArea) { -        [self removeTrackingArea:_hintArea]; -        _hintArea = nil; -    } -     -    // Forbid hinting if view is disabled -    if (!self.enabled) return; -     -    CGRect hintRect; -    [self getShortcutRect:NULL hintRect:&hintRect]; -    NSTrackingAreaOptions options = (NSTrackingMouseEnteredAndExited | NSTrackingActiveAlways | NSTrackingAssumeInside); -    _hintArea = [[NSTrackingArea alloc] initWithRect:hintRect options:options owner:self userInfo:nil]; -    [self addTrackingArea:_hintArea]; -} - -- (void)setHinting:(BOOL)flag -{ -    if (_hinting != flag) { -        _hinting = flag; -        [self setNeedsDisplay:YES]; -    } -} - -- (void)mouseEntered:(NSEvent *)event -{ -    self.hinting = YES; -} - -- (void)mouseExited:(NSEvent *)event -{ -    self.hinting = NO; -} - -void *kUserDataShortcut = &kUserDataShortcut; -void *kUserDataHint = &kUserDataHint; - -- (void)resetToolTips -{ -    if (_shortcutToolTipTag) { -        [self removeToolTip:_shortcutToolTipTag], _shortcutToolTipTag = 0; -    } -    if (_hintToolTipTag) { -        [self removeToolTip:_hintToolTipTag], _hintToolTipTag = 0; -    } -     -    if ((self.shortcutValue == nil) || self.recording || !self.enabled) return; - -    CGRect shortcutRect, hintRect; -    [self getShortcutRect:&shortcutRect hintRect:&hintRect]; -    _shortcutToolTipTag = [self addToolTipRect:shortcutRect owner:self userData:kUserDataShortcut]; -    _hintToolTipTag = [self addToolTipRect:hintRect owner:self userData:kUserDataHint]; -} - -- (NSString *)view:(NSView *)view stringForToolTip:(NSToolTipTag)tag point:(CGPoint)point userData:(void *)data -{ -    if (data == kUserDataShortcut) { -        return NSLocalizedString(@"Click to record new shortcut", @"Tooltip for non-empty shortcut button"); -    } -    else if (data == kUserDataHint) { -        return NSLocalizedString(@"Delete shortcut", @"Tooltip for hint button near the non-empty shortcut"); -    } -    return nil; -} - -#pragma mark - Event monitoring - -- (void)activateEventMonitoring:(BOOL)shouldActivate -{ -    static BOOL isActive = NO; -    if (isActive == shouldActivate) return; -    isActive = shouldActivate; -     -    static id eventMonitor = nil; -    if (shouldActivate) { -        __weak MASShortcutView *weakSelf = self; -        NSEventMask eventMask = (NSKeyDownMask | NSFlagsChangedMask); -        eventMonitor = [NSEvent addLocalMonitorForEventsMatchingMask:eventMask handler:^(NSEvent *event) { - -            MASShortcut *shortcut = [MASShortcut shortcutWithEvent:event]; -            if ((shortcut.keyCode == kVK_Delete) || (shortcut.keyCode == kVK_ForwardDelete)) { -                // Delete shortcut -                weakSelf.shortcutValue = nil; -                weakSelf.recording = NO; -                event = nil; -            } -            else if (shortcut.keyCode == kVK_Escape) { -                // Cancel recording -                weakSelf.recording = NO; -                event = nil; -            } -            else if (shortcut.shouldBypass) { -                // Command + W, Command + Q, ESC should deactivate recorder -                weakSelf.recording = NO; -            } -            else { -                // Verify possible shortcut -                if (shortcut.keyCodeString.length > 0) { -                    if (shortcut.valid) { -                        // Verify that shortcut is not used -                        NSError *error = nil; -                        if ([shortcut isTakenError:&error]) { -                            // Prevent cancel of recording when Alert window is key -                            [weakSelf activateResignObserver:NO]; -                            [weakSelf activateEventMonitoring:NO]; -                            NSString *format = NSLocalizedString(@"The key combination %@ cannot be used", -                                                                 @"Title for alert when shortcut is already used"); -                            NSRunCriticalAlertPanel([NSString stringWithFormat:format, shortcut], error.localizedDescription, -                                                    NSLocalizedString(@"OK", @"Alert button when shortcut is already used"), -                                                    nil, nil); -                            weakSelf.shortcutPlaceholder = nil; -                            [weakSelf activateResignObserver:YES]; -                            [weakSelf activateEventMonitoring:YES]; -                        } -                        else { -                            weakSelf.shortcutValue = shortcut; -                            weakSelf.recording = NO; -                        } -                    } -                    else { -                        // Key press with or without SHIFT is not valid input -                        NSBeep(); -                    } -                } -                else { -                    // User is playing with modifier keys -                    weakSelf.shortcutPlaceholder = shortcut.modifierFlagsString; -                } -                event = nil; -            } -            return event; -        }]; -    } -    else { -        [NSEvent removeMonitor:eventMonitor]; -    } -} - -- (void)activateResignObserver:(BOOL)shouldActivate -{ -    static BOOL isActive = NO; -    if (isActive == shouldActivate) return; -    isActive = shouldActivate; -     -    static id observer = nil; -    NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter]; -    if (shouldActivate) { -        __weak MASShortcutView *weakSelf = self; -        observer = [notificationCenter addObserverForName:NSWindowDidResignKeyNotification object:self.window -                                                queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *notification) { -                                                    weakSelf.recording = NO; -                                                }]; -    } -    else { -        [notificationCenter removeObserver:observer]; -    } -} - -@end | 
