diff options
Diffstat (limited to 'Framework')
| -rw-r--r-- | Framework/MASShortcutBinder.m | 25 | ||||
| -rw-r--r-- | Framework/MASShortcutBinderTests.m | 15 | 
2 files changed, 34 insertions, 6 deletions
| diff --git a/Framework/MASShortcutBinder.m b/Framework/MASShortcutBinder.m index bf85c41..9b9f017 100644 --- a/Framework/MASShortcutBinder.m +++ b/Framework/MASShortcutBinder.m @@ -23,7 +23,7 @@  - (void) dealloc  {      for (NSString *bindingName in [_actions allKeys]) { -        [self unbind:bindingName]; +        [self unbind:[self encodeBindingName:bindingName]];      }  } @@ -42,8 +42,10 @@  - (void) bindShortcutWithDefaultsKey: (NSString*) defaultsKeyName toAction: (dispatch_block_t) action  {      [_actions setObject:[action copy] forKey:defaultsKeyName]; -    [self bind:defaultsKeyName toObject:[NSUserDefaultsController sharedUserDefaultsController] -        withKeyPath:[@"values." stringByAppendingString:defaultsKeyName] options:_bindingOptions]; +    [self bind:[self encodeBindingName:defaultsKeyName] +        toObject:[NSUserDefaultsController sharedUserDefaultsController] +        withKeyPath:[@"values." stringByAppendingString:defaultsKeyName] +        options:_bindingOptions];  }  - (void) breakBindingWithDefaultsKey: (NSString*) defaultsKeyName @@ -51,7 +53,7 @@      [_shortcutMonitor unregisterShortcut:[_shortcuts objectForKey:defaultsKeyName]];      [_shortcuts removeObjectForKey:defaultsKeyName];      [_actions removeObjectForKey:defaultsKeyName]; -    [self unbind:defaultsKeyName]; +    [self unbind:[self encodeBindingName:defaultsKeyName]];  }  - (void) registerDefaultShortcuts: (NSDictionary*) defaultShortcuts @@ -74,6 +76,18 @@  #pragma mark Bindings +static NSString *const MASDotSymbolReplacement = @"__dot__"; + +- (NSString*) encodeBindingName: (NSString*) binding +{ +    return [binding stringByReplacingOccurrencesOfString:@"." withString:MASDotSymbolReplacement]; +} + +- (NSString*) decodeBindingName: (NSString*) binding +{ +    return [binding stringByReplacingOccurrencesOfString:MASDotSymbolReplacement withString:@"."]; +} +  - (BOOL) isRegisteredAction: (NSString*) name  {      return !![_actions objectForKey:name]; @@ -81,6 +95,7 @@  - (id) valueForUndefinedKey: (NSString*) key  { +    key = [self decodeBindingName:key];      return [self isRegisteredAction:key] ?          [_shortcuts objectForKey:key] :          [super valueForUndefinedKey:key]; @@ -88,6 +103,8 @@  - (void) setValue: (id) value forUndefinedKey: (NSString*) key  { +    key = [self decodeBindingName:key]; +      if (![self isRegisteredAction:key]) {          [super setValue:value forUndefinedKey:key];          return; diff --git a/Framework/MASShortcutBinderTests.m b/Framework/MASShortcutBinderTests.m index cb04532..35542d4 100644 --- a/Framework/MASShortcutBinderTests.m +++ b/Framework/MASShortcutBinderTests.m @@ -95,11 +95,22 @@ static NSString *const SampleDefaultsKey = @"sampleShortcut";          @"Bind shortcut using a default value.");  } +// The connection between user defaults and shortcuts is implemented +// using Cocoa Bindings where the dot symbol (“.”) has a special meaning. +// This means we have to escape the dot symbol used in defaults keys, +// otherwise things blow up. Details at <http://git.io/x5YS>.  - (void) testBindingsWithDotSymbol  {      static NSString *const SampleDefaultsKeyWithDotSymbol = @"sample.Shortcut"; -    XCTAssertThrows([_binder bindShortcutWithDefaultsKey:SampleDefaultsKeyWithDotSymbol toAction:^{}], -        @"Attempting to use a defaults key with a dot symbol crashes with an exception."); +    MASShortcut *shortcut = [MASShortcut shortcutWithKeyCode:1 modifierFlags:1]; +    XCTAssertNoThrow([_binder bindShortcutWithDefaultsKey:SampleDefaultsKeyWithDotSymbol toAction:^{}], +        @"Binding a shortcut to a defaults key with a dot symbol must not throw."); +    [_defaults setObject:[NSKeyedArchiver archivedDataWithRootObject:shortcut] forKey:SampleDefaultsKeyWithDotSymbol]; +    XCTAssertTrue([_monitor isShortcutRegistered:shortcut], +        @"Read a shortcut value using a defaults key with a dot symbol."); +    [_binder breakBindingWithDefaultsKey:SampleDefaultsKeyWithDotSymbol]; +    XCTAssertFalse([_monitor isShortcutRegistered:shortcut], +        @"Breaking a binding with a dot symbol.");  }  @end | 
